
V tomto článku sa podelím o to, ako som vytvoril šablónu (cookiecutter) a nastavil prostredie pre písanie REST API služby v C++ s použitím docker/docker-compose a správcu balíkov conan.
Počas ďalšieho hackathonu, kde som sa zúčastnil ako backend vývojár, sa objavila otázka, na čom napísať ďalšiu mikro službu. Všetko, čo bolo zatiaľ napísané, som vytvoril ja a môj v jazyku Python, pretože môj kolega bol odborníkom v tejto oblasti a profesionálne sa venoval vývoju backendov, zatiaľ čo ja som bol v podstate vývojár pre zabudované systémy a písal som v skvelom a hroznom C++, zatiaľ čo Python som sa len naučil na univerzite.
Takže sme mali úlohu napísať vysoko zaťaženú službu, ktorej hlavnou úlohou bol predspracovanie prichádzajúcich dát a ich zápis do databázy. A po ďalšej prestávke mi kolega navrhol, aby som, ako C++ vývojár, napísal túto službu v C++. Argumentoval tým, že to bude rýchlejšie, výkonnejšie a vôbec, porota bude nadšená z toho, ako vieme využívať zdroje tímu. Na čo som odpovedal, že som nikdy takéto veci na C++ nerobil a s ľahkosťou môžem posledných 20+ hodín venovať hľadaniu, kompilácii a skladaniu vhodných knižníc. Jednoducho povedané, zľakol som sa. Na tom sme sa dohodli a pokojne sme všetko dokončili v Pythone.
Teraz, počas nútenej izolácie, som sa rozhodol pochopiť, ako písať služby v C++. Prvá vec, ktorú som potreboval urobiť, bola určiť vhodnú knižnicu. Môj výber padol na , pretože bola napísaná v objektovo orientovanom štýle a mohla sa pochváliť dobrou dokumentáciou. Takisto sa objavila otázka voľby systému zostavenia. Predtým som pracoval len s Visual Studio, IAR a "holými" makefile. A žiadny z týchto systémov ma nenadchol, pretože som plánoval spustiť celú službu v docker kontejnere. Potom som sa rozhodol pokúsiť sa pochopiť cmake a zaujímavého správcu balíkov . Tento správca balíkov umožňoval zapísať všetky závislosti do jedného súboru
conanfile.txt
[requires]
poco/1.9.3
libpq/11.5
[generators]
cmake
a s pomocou jednoduchého príkazu „conan install .“ nainštalovať potrebné knižnice. Samozrejme, taktiež bolo potrebné vykonať zmeny v
CMakeLists.txt
include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries( ${CONAN_LIBS})
Potom som začal hľadať knižnicu na prácu s PostgreSQL, pretože s ňou som mal trochu skúseností a naše služby v Pythone s ňou interagovali. A viete, čo som zistil? Nachádza sa v POCO! Ale conan nevie, že je v POCO a nevie ju zostavovať, v repozitári je zastaraný konfiguračný súbor (už som o tejto chybe napísal tvorcom POCO). Takže budem musieť hľadať inú knižnicu.
A tak som si vybral menej populárnu knižnicu. . A mal som obrovské šťastie, už bola v conan a dokonca sa zostavovala a spojovala.
Ďalším krokom bolo napísať šablónu služby, ktorá dokáže spracovávať požiadavky.
Musíme zdediť našu triedu TemplateServerApp z Poco::Util::ServerApplication a prepísať metódu 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;
}V metóde main musíme nastaviť parametre: port, počet vlákien a veľkosť fronty. A hlavne, musíme nastaviť spracovateľ príchozích požiadaviek. Robí sa to vytvorením fabriky.
TemplateRequestHandlerFactory
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
{
return new TemplateServerAppHandler;
}
};V mojom prípade jednoducho zakaždým vytvára ten istý spracovateľ — TemplateServerAppHandler. Práve tu môžeme umiestniť našu biznis logiku.
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();
}
};Tak som vytvoril šablónu triedy na prácu s PostgreSQL. Na jednoduché SQL, napríklad na vytvorenie tabuľky, je k dispozícii metóda ExecuteSQL(). Pre zložitejšie dotazy alebo získavanie údajov je potrebné získať pripojenie cez GetConnection() a použiť API libpg. (Možno to neskôr opravím).
Databáza
#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;
};Všetky parametre na pripojenie k databáze berieme z prostredia, takže musíte tiež vytvoriť a nastaviť súbor .env
.env
DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432Môžete si pozrieť celý kód na

A prišiel posledný krok písania dockerfile a docker-compose.yml. Priznám sa, že na to ušla veľká časť času, a nie len preto, že som začiatočník, ktorý musel zakaždým prekompilovať knižnice, ale aj kvôli skrytým problémom v conan. Napríklad, aby conan stiahol, nainštaloval a postavil potrebné závislosti, nestačí stiahnuť „conan install .“, musí sa tiež zadať parameter -s compiler.libcxx=libstdc++11, inak riskujete, že dostanete kopu chýb pri linkovaní aplikácie. S touto chybou som sedel niekoľko hodín a dúfam, že tento článok pomôže iným ľuďom vyriešiť tento problém rýchlejšie.
Ďalej, po napísaní docker-compose.yml, na radu svojho kamaráta som pridal podporu a teraz si môžete získať plnohodnotnú šablónu pre REST API službu v C++, s nastaveným prostredím a so spustenou PostgreSQL, stačí zadať do konzoly „cookiecutter “. A potom „docker-compose up —build“.
Dúfam, že táto šablóna pomôže začiatočníkom na ich náročnej ceste vývoja REST API aplikácií vo veľkom a mocnom, ale tak nešikovnom jazyku, ako je C++.
Takisto veľmi odporúčam prečítať si tento článok. V ňom je podrobnejšie vysvetlené, ako pracovať s POCO a ako napísať svoj REST API servis.
Zdroj: habr.com
