해당 문서에서는 C++에서 cpprestsdk를 통해 REST API Server를 만드는 방법에 대해서 설명한다.
본 문서에서는 cpprestsdk를 사용할 것이기 때문에, 해당 SDK를 사용할 수 있도록 사전 설정이 완료되어 있어야 한다.
cpprestsdk를 사용할 수 있도록 개발 환경을 설정하는 방법에 대해서는 해당 문서를 참조한다.
개발 환경은 다음과 같은 운영체제와 IDE를 사용하였다.
코드를 작성하기 위해 Visual Studio에서 serverMain.cpp라는 소스 파일을 생성하였다.
#include <iostream>
#include <cpprest/http_listener.h>
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
http_listener
를 사용하기 위해 cpprest의 헤더 파일을 include하고 namespace를 설정한다. 초기 설정은 cpprestsdk를 사용하여 Request를 보낼때와 비교해 크게 달라진 부분은 없다.
int main() {
http_listener listener(U("http://localhost:9090")); //Server URL, Port 지정.
listener.support(methods::GET, [&listener](http_request req) {
// 처리할 내용 입력
});
}
http_listener
는 정해진 Server URL, Port에 대한 HTTP 요청을 수신하고 응답을 생성하는 HTTP 서버의 역할을 수행한다.
listener.support()
는 특정 HTTP method에 대한 요청을 받았을 때, 해당 요청에 대해 처리할 수 있도록 지원하는 역할을 한다.
try {
listener.open().then([&listener]() {cout << "\nstart!!\n" << endl; }).wait(); // server open
cout << ("서버가 실행 중입니다...") << endl;
std::cin.get();
listener.close().wait();
}
catch (const std::exception& e) {
cout << "서버 실행 과정에서 오류가 발생했습니다." << endl;
wcerr << ("Error: ") << e.what() << endl;
}
return 0;
listener.open()
함수를 통해 서버를 열고 특정 문자가 입력될 때 까지 대기하는 상태를 만들어주었다. 또한 try ~ catch ~문을 통해 exception이 발생할 경우 오류 발생 메세지를 출력하고 exception의 종류를 출력해 확인할 수 있도록 했다.
listener.support(methods::GET, [&listener](http_request req) { //support() 함수를 통해 GET방식 지정
// wcout << "uri: " << listener.uri().path() << endl;
uri uri = req.relative_uri();
auto path = uri.path();
auto query = uri.query();
wcout << "Path: " << path << endl;
wcout << "Query: " << query << endl;
auto name = uri::split_query(query)[U("name")];
if (path == U("/")) {
http_response response(status_codes::OK);
response.headers().set_content_type(U("text/plain"));
response.set_body(U("Hello, World!"));
req.reply(response);
}
else if(path == U("/hello")){ // path에 대한 개별 처리
req.reply(status_codes::OK, U("Hello, Other World!"));
}
else if (path == U("/hi")) { // path에 대한 개별 처리
req.reply(status_codes::OK, U("Hello, Another World!"));
}
else if (path == U("/name")) { // path에 대한 개별 처리
req.reply(status_codes::OK, U("Hello, ") + name + U("!"));
}
else { // 처리 구문이 존재하지 않는 요청에 대한 처리
req.reply(status_codes::NotFound);
}
});
listener.support()
내부에서 특정 path로 된 요청과 parameter에 대해 처리할 수 있도록 작성했다.
가장 먼저 서버에 대한 요청인 http_request req
를 통해 uri를 가져오고, uri를 path와 query로 분리한다. path에 따라 클라이언트가 요청한 uri의 path에 따라 처리를 분리할 수 있고, query를 split_query()
함수를 통해 분리해 각 parameter에 대한 값을 얻어 처리할 수 있다.
#include <iostream>
#include <cpprest/http_listener.h>
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
int main() {
http_listener listener(U("http://localhost:9090")); //Server URL, Port 지정.
//listener.open().then([&listener]() {cout << (U("\n start!!\n")); }).wait(); //Server open
listener.support(methods::GET, [&listener](http_request req) { //support() 함수를 통해 GET방식 지정
uri uri = req.relative_uri();
auto path = uri.path();
auto query = uri.query();
wcout << "Path: " << path << endl;
wcout << "Query: " << query << endl;
auto name = uri::split_query(query)[U("name")];
if (path == U("/")) {
http_response response(status_codes::OK);
response.headers().set_content_type(U("text/plain"));
response.set_body(U("Hello, World!"));
req.reply(response);
}
else if(path == U("/hello")){ // path에 대한 개별 처리
req.reply(status_codes::OK, U("Hello, Other World!"));
}
else if (path == U("/hi")) { // path에 대한 개별 처리
req.reply(status_codes::OK, U("Hello, Another World!"));
}
else if (path == U("/name")) { // path에 대한 개별 처리
req.reply(status_codes::OK, U("Hello, ") + name + U("!"));
}
//else if (path == U("/favicon.ico")) {} // favicon 요청에 대한 처리
else { // 처리 구문이 존재하지 않는 요청에 대한 처리
req.reply(status_codes::NotFound);
}
});
try {
listener.open().then([&listener]() {cout << "\nstart!!\n" << endl; }).wait(); // server open
cout << ("서버가 실행 중입니다...") << endl;
std::cin.get();
listener.close().wait();
}
catch (const std::exception& e) {
cout << "서버 실행 과정에서 오류가 발생했습니다." << endl;
wcerr << ("Error: ") << e.what() << endl;
}
/*while (true);
listener.close();*/
return 0;
}