강좌

C++ REST API 사용 강좌 : #2 HTTP POST (boost beast 활용)

하늘흐늘 2022. 5. 12. 15:11
반응형

이번에는 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 관련해서는 아래 포스팅 참고 부탁드립니다.

 

boost locale을 이용한 C++에서의 Multi Byte와 UTF8간의 문자열 변환

영문만 있는 경우는 문자열은 C/C++에서 UTF-8로 별도의 변환을 필요로 하지 않습니다. 하지만 한글과 같이 멀티 바이트를 사용하는 경우는 별도로 UTF-8로 인코딩 및 디코딩을 해

linkmemo.tistory.com

 

3. HTTP 프로토콜 버전을 1.1로 설정한 관계로 처리 후 연결을 종료할 것을 지정하기 위하여 connection에 "close"을 설정하였습니다. 만약 여러 번의 요청을 한 후 하나의 연결하려면 이 부분을 지운 후 연결된 상태에서 여러 번 요청하고 마지막 요청에만 설정하면 됩니다.

JSON 처리

REST API 관련 처리를 하다보면 JSON을 처리하여야 하는데 JSON을 처리하는 것은 아래와 같은 기존 포스트를 참조하면 좋습니다.

 

 

C++ boost json용 라이브러리(boost.json)

boost 1.75 이전 버전은 json을 사용하기 위하여 property_tree를 사용하였습니다. 1.75 버전부터 json을 전문적으로 지원하는 boost.json라이브러리가 생겼습니다.   boost.json을 사용하는 Hello World입니..

linkmemo.tistory.com

 

 

C++ boost json 구조체와 json 문자열간 변환 예제

boost json라이브러리를 사용하면 구조체와 json문자열 간의 상호 변환이 간단합니다. 여기서는 간단한 변환 예를 살펴보며 사용법을 알아보겠습니다. 우선 아래와 같은 간단한 예로

linkmemo.tistory.com

 

 

C++ boost json array 생성 및 파싱 예제

boost json라이브러리를 사용할 때 json array를 생성하거나 파싱하는 예제입니다. 사용법은 예제가 간단하게 되어 있는 관계로 예제를 이해하시면 됩니다. #include #include using namespace s..

linkmemo.tistory.com

 

그외 디버깅할 때 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의 예제를 활용하시면 됩니다.

 

반응형