이번에는 C++ boost beast를 활용하여 JSON을 인자로 REST API을 호출하여 데이터를 받는 예제를 살펴보도록 하겠습니다. 이 강좌는 C++ REST API 사용 강좌 : #1 HTTP GET (boost beast 활용)에서 이러지는 강좌로 설명 소스가 비슷한 관계로 해당 글에서 설명한 내용(UTF-8, 비동기 처리 등)은 이 글에 없는 관계로 해당 글도 꼭 참고 부탁드립니다.
이번에 살펴볼 소스는 아래와 같습니다.
#include <iostream>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
using namespace std;
int main(int argc, char* argv[])
{
boost::asio::io_context ioc;
boost::asio::ip::tcp::resolver resolver(ioc);
boost::beast::tcp_stream stream(ioc);
try
{
auto const host = "jsonplaceholder.typicode.com";
auto const port = "80";
auto const target = "/posts";
bool isVer1_0 = false;
int version = isVer1_0 ? 10 : 11;
auto const results = resolver.resolve(host, port);
stream.connect(results);
string urlHost = host;
urlHost += ":";
urlHost += port;
string param_json = "{"
"\"title\": \"foo\","
"\"body\" : \"bar\","
"\"userId\" : 1"
"}";
boost::beast::http::request<boost::beast::http::string_body> req{ boost::beast::http::verb::post, target, version };
req.set(boost::beast::http::field::host, urlHost);
req.set(boost::beast::http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.set(boost::beast::http::field::content_type, "application/json; charset=utf-8");
req.set(boost::beast::http::field::accept, "*/*");
req.set(boost::beast::http::field::content_length, std::to_string(param_json.length()));
req.set(boost::beast::http::field::connection, "close");
req.body() = param_json;
boost::beast::http::write(stream, req);
boost::beast::flat_buffer buffer;
boost::beast::http::response<boost::beast::http::dynamic_body> res;
boost::beast::http::read(stream, buffer, res);
string json = boost::beast::buffers_to_string(res.body().data());
cout << json << endl;
boost::beast::error_code ec;
stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
if (ec && ec != boost::beast::errc::not_connected)
{
clog << "error: " << ec.message() << endl;
return -1;
}
}
catch (std::exception const& ex) {
clog << "exception: " << ex.what() << endl;
return -1;
}
return 0;
}
실행 결과는 아래와 같습니다.
{
"title": "foo",
"body": "bar",
"userId": 1,
"id": 101
}
소스 설명
REST API를 호출할 때 JSON으로 된 인자를 넘기기 위해서는 HTTP POST 메소드를 사용합니다. 해당 소스는 HTTP POST를 사용하여 JSON인자를 넘기고 있습니다.
기존의 HTTP GET소스와 틀린점
1. boost::beast::http::verb::post을 설정하여 POST 메소드를 사용하게 설정하였으며 req.body()에 인자로 넘길 JSON을 설정하여 주었습니다. 이것과 관련된 content_length도 HTTP 헤더에 설정하여 주었습니다.
2. HTTP 헤더에서 content_type을 설정하여 주었습니다. 이렇게 설정해야 서버는 해당 요청이 JSON을 담고 있으며 UTF-8로 인코딩되어 있다는 것을 인식합니다. 실제로 보낼 때 UTF-8로 인코딩해서 보내야 합니다. UTF-8 관련해서는 아래 포스팅 참고 부탁드립니다.
3. HTTP 프로토콜 버전을 1.1로 설정한 관계로 처리 후 연결을 종료할 것을 지정하기 위하여 connection에 "close"을 설정하였습니다. 만약 여러 번의 요청을 한 후 하나의 연결하려면 이 부분을 지운 후 연결된 상태에서 여러 번 요청하고 마지막 요청에만 설정하면 됩니다.
JSON 처리
REST API 관련 처리를 하다보면 JSON을 처리하여야 하는데 JSON을 처리하는 것은 아래와 같은 기존 포스트를 참조하면 좋습니다.
그외 디버깅할 때 JSON을 보기 편하게 출력하기 원하시면 아래를 참고 하시면 좋습니다.
boost json examples Pretty
이 외의 HTTP PUT, DELETE 사용
웹브라우저에서는 HTTP GET과 POST만 사용하지만 REST API를 사용할 때는 구현에 따라 HTTP PUT과 DELETE를 사용해야 할 때도 있습니다. 이럴 때는 소스를 조금 수정하셔서 boost::beast::http::verb::post를 put이나 delete_로 설정하시고 테스트하시면 됩니다. 단 REST API 관련 테스트는 이 예제처럼 jsonplaceholder 사이트를 사용하신다면 jsonplaceholder Guide의 예제를 활용하시면 됩니다.
'강좌' 카테고리의 다른 글
C++ 코루틴(coroutine) 활용 강좌: #4 : co_yield (0) | 2022.05.24 |
---|---|
C++ 코루틴(coroutine) 활용 강좌: #3 : co_return (0) | 2022.05.23 |
C++ 코루틴(coroutine) 활용 강좌: #2 : co_await (0) | 2022.05.20 |
C++ 코루틴(coroutine) 활용 강좌: #1 시작하며 그리고 기본 개념 (0) | 2022.05.19 |
C++ REST API 사용 강좌 : #1 HTTP GET (boost beast 활용) (0) | 2022.05.11 |
C++ boost 메모리풀 강좌 #5: boost 메모리풀 할당자를 적용하여 STL 컬렉션의 성능 향상시키기 (0) | 2021.11.15 |
C++ boost 메모리풀 강좌 #4: object_pool 클래스를 이용하여 new 재정의 없이 일반 클래스에 메모리풀 적용하기 (0) | 2021.11.14 |
C++ boost 메모리풀 강좌 #3: singleton_pool 클래스를 이용하여 일반 클래스에 메모리풀 적용하기 (0) | 2021.11.13 |