티스토리 뷰
CPPRESTSDK & JSON
<XML 보다 JSON을 많이 사용하는 이유>
- 표현의 완전성과 가독성이 좋을뿐 아니라 자바 스크립트의 기본 형식이다.
- XML보다 표현이 간단하며 XML스키마나 XML DTD에 대한 구분이 필요하지 않다.
2023.07.27 추가
VisualStudio 2022 (v143) 인데 cpprestsdk 최종버전인 v142 (VisualStudio 2019) 를 설치하고
#include <cpprest/http_client.h> 를 추가하면 헤더 파일을 찾지 못하는 경우 프로젝트 속성의 "추가 포함 디렉토리" 에
$(SolutionDir)\packages\cpprestsdk.v142.2.10.15\build\native\include 를 추가한다.
위 그림은 CPPRESTSDK 가 프로젝트에 설치된 폴더 위치
2023.07.16 추가
VisualStudio 2022 (v143) 인데 cpprestsdk 최종버전이 v142 (VisualStudio 2019) 까지만 지원하는거 같다.
VisualStudio 2022 에서 컴파일 하려면 아래 그림과 같이 VisualStudio 2019로 바꿔야 한다.
VisualStudio 2019 로 바꾸지 않으면 링크 에러난다.
=====참고
1) VisualStudio2012 에서는 x86, x64 둘다 cpprestsdk 관련 헤더파일 include 하고 컴파일하면 오류난다. - 미지원?
2) VisualStudio2017 comm. 프로젝트 속성에서 헤더파일 관련 지정하지 않아도 컴파일된다.
3) 디버그 모드에서 cpprestsdk 실행 중 에러나는 경우 동일 증상이 다른 사람들도 있는듯한데 원인은 모르겠고, 프로젝트를 다시 만들어 cpprestsdk 가 동작하는지 먼저 확인 후 구 프로젝트에서 코드를 붙여넣어 해결했다. (프로젝트 설정관련 옵션을 모두 확인 해봤지만 특이사항은 없었음)
=====참고
1. VisualStudio2017 Communication 에서 아래 그림처럼 '솔루션용 NuGet패키지관리자...' 메뉴를 선택한다.
2. 아래 그림과 같이 찾아보기에서 cpprestsdk 로 검색하면 작성자가 casablancacore 인 cpprestsdk 를 선택하고 적용할 프로젝트 선택하고 설치 버튼을 클릭한다. (노란색 부분 참조)
3. 아래 그림에서 확인 클릭하면 설치 된다.
4. 아래 코드처럼 2~4행을 입력한다.
1
2
3
4
5
6
7
8
9
|
#include "stdafx.h"
#include <cpprest/http_client.h>
#include <cpprest/json.h>
#include <pplx/pplxtasks.h>
int main()
{
return 0;
}
|
cs |
5. 컴파일하면 아래 그림과 같은 에러가 난다.
6. 클래스 속성(노란색) 창에서 파란색 부분의 플랫폼도구집합을 VisualStudio2015(V14) 를 선택한다.
7. 다시 컴파일 하면 오류없이 컴파일 성공하게 된다.
아마도, VisualStudio2017 은 V141 이지만 cpprestsdk 가 140 까지만 지원하고 있는거 같다.
8. 샘플코드
프로젝트 속성은 6번 그림 참조, 특별한것 없이 콘솔응용프로그램 프로젝트 만들고 cpprestsdk 패키지 설치, 플랫폼도구집합에서 V140 으로 변경만 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fcntl.h>
#include <io.h>
#include <cpprest/http_client.h>
#include <cpprest/json.h>
using namespace std;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
void RESTTest(string_t words)
{
string_t pathString = U(R"(format=json&action=query&prop=revisions&titles=)");
pathString += uri::encode_uri(words);
pathString += U(R"(&rvprop=content)");
uri_builder b;
b.set_scheme(U("http"));
b.set_host(U("en.wikipedia.org"));
b.set_path(U("w/api.php"));
b.set_query(pathString);
http_client client(b.to_string());
auto requestTask = client.request(methods::GET);
requestTask.wait();
http_response response = requestTask.get();
string_t title;
string_t contents = U("페이지가 없습니다.");
auto v1 = response.extract_json().get();
auto v2 = v1[U("query")];
auto v3 = v2[U("pages")];
auto v4 = v3.as_object().begin();
title = (v4->second)[U("title")].as_string();
auto v5 = (v4->second)[U("revisions")];
if (!v5.is_null()) {
auto v6 = v5.as_array()[0];
contents = v6[U("*")].as_string();
}
ucout << endl << contents.c_str() << endl << endl;
ucout << U("제목 : ") << title << endl;
ucout << U("컨텐츠 사이즈 : ") << contents.size() << U(" bytes") << endl;
ucout << endl << endl;
}
int main()
{
_setmode(_fileno(stdout), _O_WTEXT); // io.h 와 fcntl.h 필요함.
// 위키피디아 결과값이 콘솔창에 출력할 수 없는 유니코드 값이 포함되어 있어 이를 보여줄 수 있도록 모드를 바꾸는 함수
RESTTest(L"keyboard"); // microsoft
_gettchar();
return 0;
}
|
cs |
<실행>
샘플코드는 Wikipedia 에서 microsoft 로 검색한 결과를 JSON 으로 받아온다.
위 코드를 기준으로 40~43행에서 cout 으로 화면 출력하고 싶으면 48행 모드변환 함수를 삭제하고 아래 처럼 하면 되고, contens 내용은 일부 cout 출력이 안되는 유니코드 값 때문에 출력하지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fcntl.h>
#include <io.h>
#include <cpprest/http_client.h>
#include <cpprest/json.h>
using namespace std;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
void RESTTest(string_t words)
{
string_t pathString = U(R"(format=json&action=query&prop=revisions&titles=)");
pathString += uri::encode_uri(words);
pathString += U(R"(&rvprop=content)");
uri_builder b;
b.set_scheme(U("http"));
b.set_host(U("en.wikipedia.org"));
b.set_path(U("w/api.php"));
b.set_query(pathString);
http_client client(b.to_string());
auto requestTask = client.request(methods::GET);
requestTask.wait();
http_response response = requestTask.get();
string_t title;
string_t contents = U("페이지가 없습니다.");
auto v1 = response.extract_json().get();
auto v2 = v1[U("query")];
auto v3 = v2[U("pages")];
auto v4 = v3.as_object().begin();
title = (v4->second)[U("title")].as_string();
auto v5 = (v4->second)[U("revisions")];
if (!v5.is_null()) {
auto v6 = v5.as_array()[0];
contents = v6[U("*")].as_string();
}
//ucout << endl << contents.c_str() << endl << endl;
//ucout << U("제목 : ") << title << endl;
//ucout << U("컨텐츠 사이즈 : ") << contents.size() << U(" bytes") << endl;
//ucout << endl << endl;
string str = "";
str.assign(title.begin(), title.end()); // wstring -> string 변환
cout << "제목 : " << str << endl;
cout << "컨텐츠 사이즈 : " << contents.size() << " bytes" << endl;
}
int main()
{
//_setmode(_fileno(stdout), _O_WTEXT); // io.h 와 fcntl.h 필요함.
// 위키피디아 결과값이 콘솔창에 출력할 수 없는 유니코드 값이 포함되어 있어 이를 보여줄 수 있도록 모드를 바꾸는 함수
RESTTest(L"keyboard"); // keyboard 로 검색
_gettchar();
return 0;
}
|
cs |
<실행>
(JSON 배열처리 예제)
err_code 부터 list 까지 객체 7개를 가지며, list 객체 배열은 2개의 객체가 있는 JSON 코드다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
{
"err_code":"000",
"err_msg":"정상",
"page_no":1,
"page_set":10,
"total_count":582,
"total_page":59,
"list":[
{
"rpt_nm":"전환사채(해외전환사채포함)발행후만기전사채취득(제7회차)",
"rcp_no":"20180611900624"
},
{
"rpt_nm":"전환사채(해외전환사채포함)발행후만기전사채취득(제7회차)",
"rcp_no":"20180607900659"
},
{
"rpt_nm":"불성실공시법인지정(공시번복)",
"rcp_no":"20180601900646"
},
{
"rpt_nm":"전환사채(해외전환사채포함)발행후만기전사채취득(제7회차)",
"rcp_no":"20180531900696"
},
{
"rpt_nm":"분기보고서 (2018.03)",
"rcp_no":"20180530000615"
},
{
"rpt_nm":"주식등의대량보유상황보고서(약식)",
"rcp_no":"20180510002841"
},
{
"rpt_nm":"불성실공시법인지정예고(공시번복)",
"rcp_no":"20180509900838"
},
{
"rpt_nm":"전환사채(해외전환사채포함)발행후만기전사채취득(제7회차)",
"rcp_no":"20180509900354"
},
{
"rpt_nm":"전환사채(해외전환사채포함)발행후만기전사채취득(제7회차)",
"rcp_no":"20180504900425"
},
{
"rpt_nm":"[기재정정]최대주주변경을수반하는주식담보제공계약체결",
"rcp_no":"20180503900749"
}]
}
|
cs |
아래 코드로 전자공시 시스템에 요청하면 위와 같은 JSON 정보를 얻으면 (실제는 더 많은 정보를 얻지만 편의상 편집해서 등록함) list 객체 배열의 rpt_nm 이름의 값을 화면에 출력하고 있다.
========================
추가>
2020.01.21 현재 기준 OPEN API서비스 도메인이 http://dart.fss.or.kr 에서 http://opendart.fss.or.kr 로 변경 예정으로 시범서비스 이후 2020.04.01 부터 openDart 로만 서비스 한다고 함.
========================
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fcntl.h>
#include <io.h>
#include <cpprest/http_client.h>
#include <cpprest/json.h>
using namespace std;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
void RESTTest3(string_t strCompanyCode)
{
string_t strDart인증키 = L"8c92==========================850d13"; // 본인의 전자공시 인증키
string_t strURL = L"http://dart.fss.or.kr/api/search.json?auth=" + strDart인증키;
strURL += L"&crp_cd=" + strCompanyCode + L"&start_dt=19990101&dsp_tp=";
uri_builder b;
http_client client(strURL);
auto requestTask = client.request(methods::GET);
requestTask.wait();
http_response response = requestTask.get();
string_t contents = U("페이지가 없습니다.");
auto v1 = response.extract_json().get(); // JSON 포맷으로 정보 받음
auto array = v1[U("list")].as_array(); // list 객체가 반복되어 배열로 저장
int n = array.size();
string_t* rpt_nm = new string_t[n];
for (int i = 0; i < n; i++)
{
rpt_nm[i] = array[i].at(U("rpt_nm")).as_string();
ucout << i+1 << U(". rpt_nam : ") << rpt_nm[i] << endl; // U(" ") 로 해야 한다. U" " 로하면 숫자로 표시됨.
}
ucout << endl << U("Total Count : ") << n << endl;
}
int main()
{
_setmode(_fileno(stdout), _O_WTEXT); // io.h 와 fcntl.h 필요함.
// 결과값이 콘솔창에 출력할 수 없는 유니코드 값이 포함되어 있어 이를 보여줄 수 있도록 모드를 바꾸는 함수
RESTTest3(L"084180");
_gettchar();
return 0;
}
|
cs |
<실행>
(std::wchar 인 string_t 를 CString 으로 변환)
MFC 사용을 위해 8행처럼 afxwin.h 추가하고, 36, 37행 코드를 추가했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fcntl.h>
#include <io.h>
#include <cpprest/http_client.h>
#include <cpprest/json.h>
#include <afxwin.h> // MFC 용
using namespace std;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
void RESTTest4(string_t strCompanyCode)
{
string_t strDart인증키 = L"8c92...70...";
string_t strURL = L"http://dart.fss.or.kr/api/search.json?auth=" + strDart인증키;
strURL += L"&crp_cd=" + strCompanyCode + L"&start_dt=19990101&dsp_tp=";
uri_builder b;
http_client client(strURL);
auto requestTask = client.request(methods::GET);
requestTask.wait();
http_response response = requestTask.get();
string_t contents = U("페이지가 없습니다.");
auto v1 = response.extract_json().get(); // JSON 포맷으로 정보 받음
auto array = v1[U("list")].as_array(); // list 객체가 반복되어 배열로 저장
int n = array.size();
string_t* rpt_nm = new string_t[n];
for (int i = 0; i < n; i++)
{
rpt_nm[i] = array[i].at(U("rpt_nm")).as_string();
ucout << i + 1 << U(". rpt_nam : ") << rpt_nm[i] << endl; // U(" ") 로 해야 한다. U" " 로하면 숫자로 표시됨.
}
ucout << endl << U("Total Count : ") << n << endl;
CString str = rpt_nm[0].c_str();
AfxMessageBox(str);
}
int main()
{
_setmode(_fileno(stdout), _O_WTEXT); // io.h 와 fcntl.h 필요함.
// 결과값이 콘솔창에 출력할 수 없는 유니코드 값이 포함되어 있어 이를 보여줄 수 있도록 모드를 바꾸는 함수
RESTTest4(L"084180");
_gettchar();
return 0;
}
|
cs |
<실행>
(string -> wstring -> string 형변환)
A2W(), W2A() 를 사용하려면 USES_CONVERSION 이 필요하고, afxwin.h 포함 해줘야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <afxwin.h> // MFC 용
#include <string>
USES_CONVERSION;
std::string s1;
std::wstring s2(A2W(s1.c_str())); // wstring <- string
for (int i = 0; i < n; i++)
{
rpt_nm[i] = array[i].at(U("rpt_nm")).as_string();
strStr = W2A(rpt_nm[i].c_str()); // string <- wstring
cout << i + 1 << ". rpt_nam : " << strStr << endl;
}
cout << endl << "Total Count : " << n << endl;
CString str = rpt_nm[0].c_str();
AfxMessageBox(str);
|
cs |