
В этой статье я расскажу о том, как создал шаблон (cookiecutter) и настроил окружение для написания REST API сервиса на С++ с использованием docker/docker-compose и пакетного менеджера conan.
Во время очередного хакатона, в котором я участвовал в качестве бекенд-разработчика, встал вопрос о том, на чем писать очередной микросервис. Все что было написано на текущий момент, писалось мной и моим на языке Python, так как мой коллега был специалистом в этой области и профессионально занимался разработкой бекендов, в то время как я вообще являлся разработчиком под встроенные системы и писал на великом и ужасном С++, а Python просто подучил в университете.
Nii et meie ülesanne oli kirjutada kõrge koormusega teenus, mille peamine ülesanne oli sisenevate andmete eeltöötlus ja nende salvestamine andmebaasi. Ja pärast järgmise suitsetamispausi pakkus üks kolleeg mulle, kui C++ arendajale, kirjutada see teenus C++ keeles. Ta põhjendas, et nii saab kiiremini, efektiivsemalt ning žürii on vaimustuses sellest, kuidas me suudame meeskonna ressursse kasutada. Sellele vastasin, et ma ei olnud kunagi selliste asjadega C++-s tegelenud ja suudan kerge vaevaga ülejäänud 20+ tundi pühenduda sobivate raamatukogude otsimisele, kompileerimisele ja sidumisele. Lihtsalt öeldes, ma kartsin. Nii me leppisime kokku ja kirjutasime kõik rahulikult Pythonis.
Praegu, sunnitud isoleerimise ajal, otsustasin ma õppida, kuidas kirjutada teenuseid C++-s. Esimene asi, mida sain teha, oli valida sobiv raamatukogu. Minu valik langes , kuna see oli kirjutatud objekti-orienteritud stiilis ja oli korraliku dokumentatsiooniga. Samuti tekkis küsimus ehitussüsteemi valimisest. Olen enne seda töötanud ainult Visual Studios, IAR-is ja „puhtal” makefile-l. Ükski neist süsteemidest ei tõmmanud mind, kuna plaanisin käivitada kogu teenuse docker-konteineris. Siis otsustasin proovida cmake'i ja huvitavat pakkemanagerit. . See pakkemanager võimaldas kõiki sõltuvusi kirjutada ühte faili.
conanfile.txt
[requires]
poco/1.9.3
libpq/11.5
[generators]
cmake
ja lihtsa käsu „conan install .” abil installida vajalikud raamatukogud. Loomulikult tuli ka teha muudatused
CMakeLists.txt
include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries( ${CONAN_LIBS})
Seejärel hakkasin otsima PostgreSQL-iga töötamiseks raamatukogu, kuna mul oli selle kasutamise osas väike kogemus ning meie teenused Pythonis suheldes kasutasid just seda. Ja tead, mida ma avastasin? See on POCO-s! Kuid conan ei tea, et see on POCO-s ja ei oska seda ehitada, repovaatetis on aegunud konfiguratsioonifail (ma olen juba sellest veast POCO loojatele kirjutanud). Näib, et tuleb otsima minna teist raamatukogu.
Ja nii langes mu valik vähem populaarsele raamatukogule . Ja mul vedas, see oli juba conan-s ja isegi ehitati ja siduti.
Järgmiseks sammuks oli teenuse šablooni kirjutamine, mis oskab töötleda päringuid.
Peame pärima oma klassi TemplateServerApp klassist Poco::Util::ServerApplication ja üle kirjutama meetodi main.
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 &)
{
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;
}Peamises meetodis peame määrama parameetrid: port, lõimede arv ja järjekorra suurus. Ja mis kõige tähtsam, peame määrama sisendi päringute töötleja. Seda tehakse tehase loomise kaudu.
TemplateRequestHandlerFactory
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
{
return new TemplateServerAppHandler;
}
};Minu puhul loob see lihtsalt iga kord sama töötleja — TemplateServerAppHandler. Just siin saame me paigutada meie äriloogika.
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();
}
};Olen samuti loonud klassi šablooni PostgreSQL-iga töötamiseks. Lihtsa SQL-i, näiteks tabeli loomise jaoks, on olemas meetod ExecuteSQL(). Tõsisemate päringute või andmete saamise jaoks tuleb luua ühendus meetodi kaudu GetConnection() ja kasutada libpg API-t. (Võib-olla parandan selle ebaõigluse hiljem).
Andmebaas
#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;
};Kõik andmebaasi ühendamise parameetrid saadakse keskkonnast, seega peate ka looma ja konfigureerima faili .env
.env
DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432Saate vaadata kogu koodi

Ja on jõudnud viimase etapi kirjutamine dockerfile ja docker-compose.yml. Olen aus, selleks kulus suurem osa ajast, ja mitte ainult sellepärast, et olen algaja, kes pidi iga kord raamatukogusid uuesti kompileerima, vaid ka conan'i takistuste tõttu. Näiteks, et conan saaks vajalikud sõltuvused alla laadida, installida ja üles ehitada, ei piisa vaid "conan install ." käsust, vaid peab lisama parameetri -s compiler.libcxx=libstdc++11, vastasel juhul riskite saada hulga vigu rakenduse linkimise etapil. Veetsin selle vea tõttu mitu tundi ning loodan, et see artikkel aitab teistel inimestel selle probleemi kiiremini lahendada.
Seejärel, pärast docker-compose.yml kirjutamist, oma sõbra soovitusel lisasin toetuse ja nüüd saate endale täieõigusliku шаблoni REST API teenuse jaoks C++ keeles koos seadistatud keskkonna ja PostgreSQL-iga, kirjutades lihtsalt terminalisse "cookiecutter ". Ja seejärel "docker-compose up —build".
Loodan, et see шаблон aitab algajaid nende raskel teel REST API rakenduste arendamisel suur ja vägev, kuid nii raske keele nagu C++ puhul.
Samuti soovitan tungivalt lugeda artiklis. Selles selgitatakse, kuidas töötada POCO-ga ja kirjutada oma REST API teenus.
Allikas: habr.com
