Microservices in C ++. Fiction or reality?



In this article I will talk about how I created a cookiecutter and set up the environment for writing a REST API service in C ++ using docker / docker-compose and the conan package manager.


During the next hackathon, in which I participated as a backend developer, the question arose about what to write the next microservice on. Everything that was written at the moment was written by me and my friend in Python, as my colleague was an expert in this field and was professionally involved in the development of backends, while I was generally a developer for embedded systems and wrote in great and terrible C ++, and Python just learned at the university.


So, we faced the task of writing a highly loaded service, the main task of which was the preprocessing of the data coming to it and writing it to the database. And after another smoke break, a friend suggested that I, as a C ++ developer, write this service on the pluses. Arguing this by saying that it will be faster, more productive, and indeed, the jury will be delighted with how we can manage the resources of the team. To which I replied that I had never done such things in C ++ and I could easily devote the remaining 20+ hours to finding, compiling and linking suitable libraries. Simply put, I got scared. That's what they decided and calmly added everything to Python.


, , ++. , , . POCO, - , . , . Visual Studio, IAR «» makefile. , docker-. cmake conan.

conanfile.txt
[requires]
poco/1.9.3
libpq/11.5

[generators]
cmake

and with the simple command “conan install.” install the necessary libraries. Naturally, changes were also required in

CMakeLists.txt
include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})

After that, I started looking for a library for working with PostgreSQL, since it was with it that I had little experience, and it was with it that our Python services interacted. And you know what I found out? She is in POCO! But conan does not know that it is in POCO and does not know how to build it, the obsolete configuration file is in the repository (I already wrote about this error to the creators of POCO). So, you have to look for another library.

And then my choice fell on the less popular libpg library . And I was incredibly lucky, she was already in conan and even assembled and assembled.

The next step was to write a service template that can handle requests.
We must inherit our TemplateServerApp class from Poco :: Util :: ServerApplication and override the main method.

TemplateServerApp
#pragma once

#include <string>
#include <vector>
#include <Poco/Util/ServerApplication.h>

class TemplateServerApp : public Poco::Util::ServerApplication
{
    protected:
        int main(const std::vector<std::string> &);
};

int TemplateServerApp::main(const vector<string> &)
{
    HTTPServerParams* pParams = new HTTPServerParams;

    pParams->setMaxQueued(100);
    pParams->setMaxThreads(16);

    HTTPServer s(new TemplateRequestHandlerFactory, ServerSocket(8000), pParams);

    s.start();
    cerr << "Server started" << endl;

    waitForTerminationRequest();  // wait for CTRL-C or kill

    cerr << "Shutting down..." << endl;
    s.stop();

    return Application::EXIT_OK;
}


In the main method, we must set the parameters: port, number of threads and queue size. And most importantly, you must specify an incoming request handler. This is done through the creation of a factory.

TemplateRequestHandlerFactory
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
    {
        return new TemplateServerAppHandler;
    }
};


In my case, it just creates the same handler every time - TemplateServerAppHandler. It is here that we can position our business logic.

TemplateServerAppHandler
class TemplateServerAppHandler : public HTTPRequestHandler
{
public:
    void handleRequest(HTTPServerRequest &req, HTTPServerResponse &resp)
    {
        URI uri(req.getURI());
        string method = req.getMethod();

        cerr << "URI: " << uri.toString() << endl;
        cerr << "Method: " << req.getMethod() << endl;

        StringTokenizer tokenizer(uri.getPath(), "/", StringTokenizer::TOK_TRIM);
        HTMLForm form(req,req.stream());

        if(!method.compare("POST"))
        {
            cerr << "POST" << endl;
        }
        else if(!method.compare("PUT"))
        {
            cerr << "PUT" << endl;
        }
        else if(!method.compare("DELETE"))
        {
            cerr << "DELETE" << endl;
        }

        resp.setStatus(HTTPResponse::HTTP_OK);
        resp.setContentType("application/json");
        ostream& out = resp.send();

        out << "{\"hello\":\"heh\"}" << endl;
        out.flush();
    }
};

I also created a class template for working with PostgreSQL. In order to execute simple SQL, for example to create a table, there is an ExecuteSQL () method . For more complex queries or data retrieval, you will have to get connection via GetConnection () and use the libpg API. (Maybe then I will correct this injustice).

Database
#pragma once

#include <memory>
#include <mutex>
#include <libpq-fe.h>

class Database
{
public:
    Database();
    std::shared_ptr<PGconn> GetConnection() const;
    bool ExecuteSQL(const std::string& sql);

private:
    void establish_connection();
    void LoadEnvVariables();

    std::string m_dbhost;
    int         m_dbport;
    std::string m_dbname;
    std::string m_dbuser;
    std::string m_dbpass;

    std::shared_ptr<PGconn>  m_connection;
};

All parameters for connecting to the database are taken from the environment, so you also need to create and configure the .env file

.env
DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432


You can see all the code on the github.



dockerfile docker-compose.yml. , , , , , - conan. , , conan , , «conan install .», -s compiler.libcxx=libstdc++11, . , , .


, docker-compose.yml, cookiecutter REST API ++, c , PostgreSQL, «cookiecutter https://github.com/KovalevVasiliy/cpp_rest_api_template.git». «docker-compose up --build».


, REST API , , ++.
, . POCO REST API .


All Articles