[C++] REST/HTTP API server/client
Updated:
개요
- Microsoft에서 만든 C++ REST SDK를 사용
- Reference
- REST
빌드
- ninja-build 설치
dnf config-manager --set-enabled crb
dnf install ninja-build
- 공통
git clone https://github.com/microsoft/cpprestsdk.git
cd cpprestsdk/
git submodule update --init
- debug 빌드
mkdir build.debug
cd build.debug
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Debug
ninja
- release 빌드
mkdir build.release
cd build.release/
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Release
ninja
- 정적 라이브러리 빌드
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=0
- 테스트
cd Release/Binaries
./test_runner *_test.so
- 헤더파일 위치
Release/include/
- 라이브러리 위치
Release/Binaries
예제
- 코드
-
#include "cpprest/asyncrt_utils.h" #include "cpprest/containerstream.h" #include "cpprest/filestream.h" #include "cpprest/http_client.h" #include "cpprest/http_listener.h" #include "cpprest/json.h" #include "cpprest/producerconsumerstream.h" #include "cpprest/uri.h" #include <future> using namespace std; class Handler { private: web::http::experimental::listener::http_listener listener; void Get(web::http::http_request request); void Post(web::http::http_request request); void Put(web::http::http_request request); void Delete(web::http::http_request request); public: Handler(const web::http::uri &address); virtual ~Handler() = default; pplx::task<void> Open() { return this->listener.open(); } pplx::task<void> Close() { return this->listener.close(); } }; Handler::Handler(const web::http::uri &address) : listener(address) { this->listener.support(web::http::methods::GET, bind(&Handler::Get, this, placeholders::_1)); this->listener.support(web::http::methods::PUT, bind(&Handler::Put, this, placeholders::_1)); this->listener.support(web::http::methods::POST, bind(&Handler::Post, this, placeholders::_1)); this->listener.support(web::http::methods::DEL, bind(&Handler::Delete, this, placeholders::_1)); } void Handler::Get(web::http::http_request request) { ucout << "----- server get start -----" << endl; // ucout << request.to_string() << endl; ucout << "\tmethod : (" << request.method() << ")" << endl; ucout << "\trequest_uri : (" << request.request_uri().to_string() << ")" << endl; ucout << "\trelative_uri : (" << request.relative_uri().to_string() << ")" << endl; ucout << "\tabsolute_uri : (" << request.absolute_uri().to_string() << ")" << endl; ucout << "\tpath : (" << request.relative_uri().path() << ")" << endl; for (const auto &iter : web::http::uri::split_path(request.relative_uri().path())) { ucout << "\tpath : (" << iter << ")" << endl; } ucout << "\tquery : (" << request.request_uri().query() << ")" << endl; for (const auto &iter : web::http::uri::split_query(request.request_uri().query())) { ucout << "\tquery : (" << iter.first << ", " << iter.second << ")" << endl; } auto response = web::json::value::object(); response["a"] = web::json::value::string("1"); response["b"] = web::json::value::number(2); response["c"] = web::json::value::boolean(true); response["d"] = web::json::value::null(); response["e"] = web::json::value::array(); request.reply(web::http::status_codes::OK, response); ucout << "----- server get end -----" << endl << endl << endl; }; void Handler::Post(web::http::http_request request) { ucout << "----- server post start -----" << endl; // ucout << request.to_string() << endl; ucout << "\theaders start" << endl; for (const auto &iter : request.headers()) { ucout << "\t\t(" << iter.first << "), (" << iter.second << ")" << endl; } ucout << "\theaders end" << endl; request.extract_json().then([=](web::json::value body) { ucout << "----- server post body start -----" << endl; ucout << "\t(" << body.serialize() << ")" << endl; ucout << "\t(" << body.at("a").as_integer() << ")" << endl; ucout << "----- server post body end -----" << endl << endl << endl; auto response = web::json::value::object(); response["id"] = web::json::value::number(1); request.reply(web::http::status_codes::Created, response); }); ucout << "----- server post end -----" << endl << endl << endl; }; void Handler::Put(web::http::http_request request) { ucout << "----- server put start -----" << endl; // ucout << request.to_string() << endl; request.extract_json(true).then([=](web::json::value body) { ucout << "----- server put body start -----" << endl; ucout << "\t(" << body.serialize() << ")" << endl; ucout << "\t(" << body.at("b").as_integer() << ")" << endl; ucout << "----- server put body end -----" << endl << endl << endl; utility::string_t response = "put response"; request.reply(web::http::status_codes::OK, response); }); ucout << "----- server put end -----" << endl << endl << endl; }; void Handler::Delete(web::http::http_request request) { ucout << "----- server delete start -----" << endl; // ucout << request.to_string() << endl; cout << "\tid : (" << web::http::uri::split_path(request.relative_uri().path())[1] << ")" << endl; request.reply(web::http::status_codes::NoContent); ucout << "----- server delete end -----" << endl << endl << endl; }; int main() { ucout << "main start" << endl << endl; auto handler = make_unique<Handler>(U("http://0.0.0.0:10000")); auto server_start = [&handler]() { handler->Open().wait(); }; auto server_stop = [&handler]() { handler->Close().wait(); }; auto client_job = []() { web::http::client::http_client g("http://127.0.0.1:10000"); auto requestGet = web::http::client::http_client(U("http://127.0.0.1:10000")) .request(web::http::methods::GET, web::uri_builder(U("uri-1")) .append_path(U("uri-2")) .append_query(U("id-1"), 1) .append_query(U("id-2"), 2) .to_string()) .then([](web::http::http_response response) { ucout << "----- client get start -----" << endl; ucout << "\tstatus_code : (" << response.status_code() << ")" << endl; return response.extract_json(); }) .then([](web::json::value body) { ucout << "\tbody : (" << body.serialize() << ")" << endl; ucout << "----- client get end -----" << endl << endl << endl << endl << endl; }); requestGet.wait(); auto requestPost = web::http::client::http_client(U("http://127.0.0.1:10000")) .request(web::http::methods::POST, web::uri_builder(U("uri-1")) .append_path(U("uri-2")) .to_string(), "{\"a\" : 1}", U("application/json")) .then([](web::http::http_response response) { ucout << "----- client post start -----" << endl; ucout << "\tstatus_code : (" << response.status_code() << ")" << endl; return response.extract_json(); }) .then([](web::json::value body) { ucout << "\tbody : (" << body.serialize() << ")" << endl; ucout << "----- client post end -----" << endl << endl << endl << endl << endl; }); requestPost.wait(); auto requestPut = web::http::client::http_client(U("http://127.0.0.1:10000")) .request(web::http::methods::PUT, web::uri_builder(U("uri-1")) .append_path(U("uri-2")) .to_string(), "{\"b\" : 1}", U("application/json")) .then([](web::http::http_response response) { ucout << "----- client put start -----" << endl; ucout << "\tstatus_code : (" << response.status_code() << ")" << endl; return response.extract_string(); }) .then([](utility::string_t body) { ucout << "\tbody : (" << body << ")" << endl; ucout << "----- client put end -----" << endl << endl << endl << endl << endl; }); requestPut.wait(); auto requestDelete = web::http::client::http_client(U("http://127.0.0.1:10000")) .request(web::http::methods::DEL, web::uri_builder(U("uri-1")) .append_path(U("1")) .to_string()) .then([](web::http::http_response response) { ucout << "----- client delete start -----" << endl; ucout << "\tstatus_code : (" << response.status_code() << ")" << endl; ucout << "----- client delete end -----" << endl << endl; }); requestDelete.wait(); }; server_start(); client_job(); server_stop(); ucout << endl << "main end" << endl; return EXIT_SUCCESS; }
-
- 컴파일
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/.../cpprestsdk/build.debug/Release/Binaries/
g++ -g -Wall -o main main.cpp -I/.../cpprestsdk/Release/include/ -L/.../cpprestsdk/build.debug/Release/Binaries/ -lcrypto -lcpprest
- 실행 결과
-
main start ----- server get start ----- method : (GET) request_uri : (/uri-1/uri-2?id-1=1&id-2=2) relative_uri : (/uri-1/uri-2?id-1=1&id-2=2) absolute_uri : (/uri-1/uri-2?id-1=1&id-2=2) path : (/uri-1/uri-2) path : (uri-1) path : (uri-2) query : (id-1=1&id-2=2) query : (id-1, 1) query : (id-2, 2) ----- server get end ----- ----- client get start ----- status_code : (200) body : ({"a":"1","b":2,"c":true,"d":null,"e":[]}) ----- client get end ----- ----- server post start ----- headers start (Connection), (Keep-Alive) (Content-Length), (9) (Content-Type), (application/json) (Host), (127.0.0.1:10000) (User-Agent), (cpprestsdk/2.10.18) headers end ----- server post end ----- ----- server post body start ----- ({"a":1}) (1) ----- server post body end ----- ----- client post start ----- status_code : (201) body : ({"id":1}) ----- client post end ----- ----- server put start ----- ----- server put end ----- ----- server put body start ----- ({"b":1}) (1) ----- server put body end ----- ----- client put start ----- status_code : (200) body : (put response) ----- client put end ----- ----- server delete start ----- id : (1) ----- server delete end ----- ----- client delete start ----- status_code : (204) ----- client delete end ----- main end
-