본문 바로가기
C_C++

C++ : Poco라이브러리로 REST API 서버 만들기(2)

by taekho 2026. 6. 1.

 

1. POCO 라이브러리를 설치합니다.

https://pocoproject.org/download.html

 

POCO C++ Libraries - Simplify C++ Development

The POCO C++ Libraries are powerful cross-platform and open source C++ class libraries for building network- and internet-based applications that run on desktop, server, mobile, IoT and embedded systems.

pocoproject.org

 

2. vcpkg를 이용하여 쉽게 설치할 수 있습니다.

    - vcpkg를 설치합니다.

    - vcpkg search poco를 실행한다.

    - vcpkg install poco[core,json,net]:x64-windows으로 필요한 라이브러리를 설치한다.

    - vcpkg install mariadb-connector-cpp:x64-windows로 mariaDB C++ Connector를

      설치한다.(SQL Server로 mariaDB Server를 사용합니다)

 

3. Database.h 파일을 추가합니다.

#pragma once

#include <mariadb/conncpp.hpp>

#include <memory>

class Database
{
public:
    static std::unique_ptr<sql::Connection> GetConnection();

private:
    static constexpr const char* URL = "jdbc:mariadb://127.0.0.1:3306/database1";

    static constexpr const char* USER = "user1";

    static constexpr const char* PASSWORD = "password1";
};

 

4. Database.cpp 파일을 추가합니다.

#include "Database.h"
#include <iostream>
#include <cstdlib>

std::unique_ptr<sql::Connection>
Database::GetConnection()
{
 
    sql::SQLString url(URL);
    sql::Properties properties(
        {
            {"user", USER},
            {"password", PASSWORD},
        });

    _putenv_s("MARIADB_TLS_DISABLE_PEER_VERIFICATION", "1");

    sql::Driver* driver = sql::mariadb::get_driver_instance();

    std::unique_ptr<sql::Connection> conn;
    try {
        conn.reset(driver->connect(url, properties));
    }
    catch (sql::SQLException& e)
    {
        std::cerr << "Connection error: " << e.what() << std::endl;
        return nullptr;
		}
    return conn;
}

 

5. MemberHandler.h 파일을 추가합니다.

#pragma once

#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>

class MemberHandler : public Poco::Net::HTTPRequestHandler
{
public:
    void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) override;
};

 


6. MemberHandler.cpp 파일을 추가합니다.

#include "MemberHandler.h"
#include "Database.h"

#include <Poco/JSON/Object.h>
#include <Poco/JSON/Array.h>
#include <Poco/JSON/Stringifier.h>
#include <Poco/Dynamic/Var.h>
#include <Poco/JSON/Parser.h>

//#include <mysql/jdbc.h>
#include <mariadb/conncpp.hpp>
#include <sstream>

using namespace Poco::JSON;
using namespace Poco::Net;

void MemberHandler::handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
    if (request.getMethod() == "GET")
    {
        std::cout << "GET request received" << std::endl;

        std::string uri = request.getURI();

        if (uri == "/")
        {
            Poco::JSON::Object result;

            result.set("success", false);
            result.set("message", "POCO REST Server Running");

            std::stringstream ss;

            result.stringify(ss);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            response.setContentType("application/json");

            response.send() << ss.str();
        }
        else if (uri == "/members")
        {
            auto conn = Database::GetConnection();

            std::unique_ptr<sql::PreparedStatement> pstmt{ conn->prepareStatement("SELECT id, name, image_id FROM member") };

            std::unique_ptr<sql::ResultSet> rs{ pstmt->executeQuery() };

            Array arr;

            while (rs->next())
            {
                Object::Ptr obj = new Object;
                auto setStringOrNull = [&](const std::string& key)
                    {
                        auto value = rs->getString(key);
                        if (rs->wasNull())
                            obj->set(key, Poco::Dynamic::Var());
                        else
                            obj->set(key, std::string(value.c_str()));
                    };

                obj->set("id", rs->getInt("id"));
                setStringOrNull("name");                
                obj->set("image_id", rs->getInt("image_id"));


                arr.add(obj);
            }

            response.setContentType("application/json");
            response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);

            arr.stringify(response.send());
        }
    }

    if (request.getMethod() == "POST")
    {
        std::cout << "POST request received" << std::endl;

        std::string uri = request.getURI();

        if (uri == "/members")
        {
            std::istream& in = request.stream();

            std::string body(std::istreambuf_iterator<char>(in), {});

            Parser parser;
            Poco::Dynamic::Var result = parser.parse(body);
            Object::Ptr j = result.extract<Object::Ptr>();

            auto conn = Database::GetConnection();

            auto pstmt =
                conn->prepareStatement(
                    "INSERT INTO member (name, image_id) VALUES (?, ?)");

            pstmt->setString(1, j->getValue<std::string>("name"));
            pstmt->setInt(2, j->getValue<int>("image_id"));

            pstmt->executeUpdate();

            Object obj;

            obj.set("success", true);
            obj.set("message", "member created");

            response.setStatus(Poco::Net::HTTPResponse::HTTP_CREATED);

            response.setContentType("application/json");

            std::stringstream ss;

            obj.stringify(ss);

            response.send() << ss.str();
        }
        else
        {
            Poco::JSON::Object error;

            error.set("success", false);

            error.set("message", "invalid uri");

            std::stringstream out;

            error.stringify(out);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            response.setContentType("application/json");

            response.send() << out.str();
        }
    }

    if (request.getMethod() == "PUT")
    {
        std::cout << "PUT request received" << std::endl;

        std::string uri = request.getURI();

        std::vector<std::string> parts;

        std::stringstream ss(uri);

        std::string part;

        while (std::getline(ss, part, '/'))
        {
            if (!part.empty())
            {
                parts.push_back(part);
            }
        }

        if (parts.size() == 2 && parts[0] == "members")
        {
            int id = std::stoi(parts[1]);

            std::istream& in = request.stream();

            std::string body(std::istreambuf_iterator<char>(in), {});

            Poco::JSON::Parser parser;

            auto parsed = parser.parse(body);

            auto obj = parsed.extract<Poco::JSON::Object::Ptr>();

            std::string name = obj->getValue<std::string>("name");

            int image_id = obj->getValue<int>("image_id");

            auto conn = Database::GetConnection();

            auto pstmt = conn->prepareStatement("UPDATE member SET name=?, image_id=? WHERE id=?");

            pstmt->setString(1, name);
            pstmt->setInt(2, image_id);

            pstmt->setInt(3, id);

            pstmt->executeUpdate();

            Poco::JSON::Object result;

            result.set("success", true);
            result.set("message", "member updated");

            result.set("id", id);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);

            response.setContentType("application/json");

            std::stringstream out;

            result.stringify(out);

            response.send() << out.str();
        }
        else
        {
            Poco::JSON::Object error;

            error.set("success", false);

            error.set("message", "invalid uri");

            std::stringstream out;

            error.stringify(out);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            response.setContentType("application/json");

            response.send() << out.str();
        }
    }

    if (request.getMethod() == "DELETE")
    {
        std::cout << "DELETE request received" << std::endl;

        std::string uri = request.getURI(); 
        
        std::vector<std::string> parts;

        std::stringstream ss(uri);

        std::string part;

        while (std::getline(ss, part, '/'))
        {
            if (!part.empty())
            {
                parts.push_back(part);
            }
        }

        if (parts.size() == 2 && parts[0] == "members")
        {
            int id = std::stoi(parts[1]);

            auto conn = Database::GetConnection();

            auto pstmt = conn->prepareStatement("DELETE FROM member WHERE id=?");

            pstmt->setInt(1, id);

            pstmt->executeUpdate();

            Poco::JSON::Object result;

            result.set("success", true);

            result.set("message", "member deleted");

            std::stringstream out;

            result.stringify(out);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);

            response.setContentType("application/json");

            response.send() << out.str();
        }
        else
        {
            Poco::JSON::Object error;

            error.set("success", false);

            error.set("message", "invalid uri");

            std::stringstream out;

            error.stringify(out);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            response.setContentType("application/json");

            response.send() << out.str();
        }

    }
}

 

7. ImageHandler.h 파일을 추가합니다.

#pragma once

#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>

class ImageHandler : public Poco::Net::HTTPRequestHandler
{
public:
    void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) override;
};

 

8. ImageHandler.cpp 파일을 추가합니다.

#include "ImageHandler.h"
#include "Database.h"

#include "Poco/FileStream.h"

#include <Poco/JSON/Object.h>
#include <Poco/JSON/Array.h>
#include <Poco/JSON/Stringifier.h>
#include <Poco/Dynamic/Var.h>
#include <Poco/JSON/Parser.h>

using namespace Poco::JSON;
using namespace Poco::Net;


void ImageHandler::handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
    response.setContentType("application/json");

    auto conn = Database::GetConnection();

    if (request.getMethod() == "GET")
    {
        std::cout << "GET request received" << std::endl;

        std::string uri = request.getURI(); 

        std::vector<std::string> parts;

        std::stringstream ss(uri);

        std::string part;

        while (std::getline(ss, part, '/'))
        {
            if (!part.empty())
            {
                parts.push_back(part);
            }
        }

        if (parts.size() == 0)
        {
            Poco::JSON::Object result;

            result.set("success", false);
            result.set("message", "POCO REST Server Running");

            std::stringstream ss;

            result.stringify(ss);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            response.setContentType("application/json");

            response.send() << ss.str();
        }
        else if (parts.size() == 1 && parts[0] == "images")
        {
            std::unique_ptr<sql::PreparedStatement> pstmt{ conn->prepareStatement("SELECT id, file FROM image") };

            std::unique_ptr<sql::ResultSet> rs{ pstmt->executeQuery() };

            Array arr;

            while (rs->next())
            {
                Object::Ptr obj = new Object;
                auto setStringOrNull = [&](const std::string& key)
                    {
                        auto value = rs->getString(key);
                        if (rs->wasNull())
                            obj->set(key, Poco::Dynamic::Var());
                        else
                            obj->set(key, std::string(value.c_str()));
                    };

                obj->set("id", rs->getInt("id"));
                setStringOrNull("file");

                arr.add(obj);
            }

            response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
            arr.stringify(response.send());
        }
        else if (parts.size() == 2 && parts[0] == "images")
        {
            int id = std::stoi(parts[1]);
            std::string filename;

                auto pstmt = std::unique_ptr<sql::PreparedStatement>{ conn->prepareStatement("SELECT file FROM image WHERE id=?") };

                pstmt->setInt(1, id);

                auto res = std::unique_ptr<sql::ResultSet>{ pstmt->executeQuery() };

                if (res->next())
                {                    
                    filename = res->getString("file");
                }
            
                response.setContentType("image/jpg");
            
                Poco::FileInputStream fis(filename, std::ios::binary);
            
                std::ostream& out = response.send();
            
                char buffer[4096];
            
                while (fis.good())
                {
                    fis.read(buffer, sizeof(buffer));
            
                    std::streamsize n = fis.gcount();
            
                    if (n > 0)
                        out.write(buffer, n);
                }

        }

    }

    if (request.getMethod() == "POST")
    {
        std::cout << "POST request received" << std::endl;

        std::string uri = request.getURI();

        if (uri == "/images")
        {
            std::istream& in = request.stream();

            std::string body(std::istreambuf_iterator<char>(in), {});

            Parser parser;
            Poco::Dynamic::Var result = parser.parse(body);
            Object::Ptr j = result.extract<Object::Ptr>();

            auto conn = Database::GetConnection();

            auto pstmt =
                conn->prepareStatement(
                    "INSERT INTO member (file VALUES (?)");

            pstmt->setString(1, j->getValue<std::string>("file"));

            pstmt->executeUpdate();

            Object obj;

            obj.set("success", true);
            obj.set("message", "image created");

            response.setStatus(Poco::Net::HTTPResponse::HTTP_CREATED);

            response.setContentType("application/json");

            std::stringstream ss;

            obj.stringify(ss);

            response.send() << ss.str();
        }
        else
        {
            Poco::JSON::Object error;

            error.set("success", false);

            error.set("message", "invalid uri");

            std::stringstream out;

            error.stringify(out);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            response.setContentType("application/json");

            response.send() << out.str();
        }
    }

    if (request.getMethod() == "PUT")
    {
        std::cout << "PUT request received" << std::endl;

        std::string uri = request.getURI();

        std::vector<std::string> parts;

        std::stringstream ss(uri);

        std::string part;

        while (std::getline(ss, part, '/'))
        {
            if (!part.empty())
            {
                parts.push_back(part);
            }
        }

        if (parts.size() == 2 && parts[0] == "images")
        {
            int id = std::stoi(parts[1]);

            std::istream& in = request.stream();

            std::string body(std::istreambuf_iterator<char>(in), {});

            Poco::JSON::Parser parser;

            auto parsed = parser.parse(body);

            auto obj = parsed.extract<Poco::JSON::Object::Ptr>();

            std::string file = obj->getValue<std::string>("file");

            auto conn = Database::GetConnection();

            auto pstmt = conn->prepareStatement("UPDATE image SET file=? WHERE id=?");

            pstmt->setString(1, file);

            pstmt->setInt(3, id);

            pstmt->executeUpdate();

            Poco::JSON::Object result;

            result.set("success", true);
            result.set("message", "image updated");

            result.set("id", id);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);

            response.setContentType("application/json");

            std::stringstream out;

            result.stringify(out);

            response.send() << out.str();
        }
        else
        {
            Poco::JSON::Object error;

            error.set("success", false);

            error.set("message", "invalid uri");

            std::stringstream out;

            error.stringify(out);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            response.setContentType("application/json");

            response.send() << out.str();
        }
    }

    if (request.getMethod() == "DELETE")
    {
        std::cout << "DELETE request received" << std::endl;

        std::string uri = request.getURI();

        std::vector<std::string> parts;

        std::stringstream ss(uri);

        std::string part;

        while (std::getline(ss, part, '/'))
        {
            if (!part.empty())
            {
                parts.push_back(part);
            }
        }

        if (parts.size() == 2 && parts[0] == "images")
        {
            int id = std::stoi(parts[1]);

            auto conn = Database::GetConnection();

            auto pstmt = conn->prepareStatement("DELETE FROM image WHERE id=?");

            pstmt->setInt(1, id);

            pstmt->executeUpdate();

            Poco::JSON::Object result;

            result.set("success", true);

            result.set("message", "image deleted");

            std::stringstream out;

            result.stringify(out);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);

            response.setContentType("application/json");

            response.send() << out.str();
        }
        else
        {
            Poco::JSON::Object error;

            error.set("success", false);

            error.set("message", "invalid uri");

            std::stringstream out;

            error.stringify(out);

            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            response.setContentType("application/json");

            response.send() << out.str();
        }

    }
}

 

9. NullHandler.h 파일을 추가합니다.

#pragma once

#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>

class NullHandler : public Poco::Net::HTTPRequestHandler
{
public:

    void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) override;
};

 

10. NullHandler.cpp 파일을 추가합니다.

#include "NullHandler.h"

#include <Poco/JSON/Object.h>
#include <Poco/JSON/Stringifier.h>

void NullHandler::handleRequest(
    Poco::Net::HTTPServerRequest& request,
    Poco::Net::HTTPServerResponse& response
)
{
    Poco::JSON::Object json;

    json.set("success", false);
    json.set("error", "Invalid API endpoint");
    json.set("uri", request.getURI());

    response.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);

    response.setContentType("application/json");
    
    std::ostream& os = response.send();

    json.stringify(os);
}

 

11. Factory.h 파일을 추가합니다.

#pragma once

#include <memory>
#include "MemberHandler.h"
#include "ImageHandler.h"
#include "NullHandler.h"

#include <Poco/Net/HTTPRequestHandlerFactory.h>


class Factory : public Poco::Net::HTTPRequestHandlerFactory
{
public:    
    Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request) override
    {
        constexpr auto MEMBERS = "/members/";
        constexpr auto IMAGES = "/image/";

        std::string uri = request.getURI();

        if (uri == "/members" || uri.starts_with(MEMBERS))
            return new MemberHandler();
 
        if (uri == "/images" || uri.starts_with(IMAGES))
            return new ImageHandler();

        return new NullHandler();
    }
};

 

12. main.cpp파일을 추가합니다.

#include "MemberHandler.h"
#include "ImageHandler.h"
#include "Factory.h"
#include <Poco/Net/HTTPServer.h>
#include <Poco/Net/ServerSocket.h>

#include <iostream>

using namespace Poco::Net;

int main()
{
    ServerSocket socket(8080);

    HTTPServer server(new Factory(), socket, new HTTPServerParams);

    server.start();

    std::cout << "REST Server Start : 8080\n";

    getchar();

    server.stop();

    return 0;
}

 

13. 프로젝트를 실행합니다.

 

* 참고

- C++ : Poco라이브러리로 REST API 서버 만들기(1)

https://taekho.tistory.com/41

 

C++ : Poco라이브러리로 REST API 서버 만들기(1)

1. POCO 라이브러리를 설치합니다.https://pocoproject.org/download.html POCO C++ Libraries - Simplify C++ DevelopmentThe POCO C++ Libraries are powerful cross-platform and open source C++ class libraries for building network- and internet-based ap

taekho.tistory.com

 

- C++ : Poco라이브러리로 REST API 서버 만들기(3)

https://taekho.tistory.com/43