I denne artikkelen vil jeg snakke om hvordan jeg opprettet en mal (cookiecutter) og satte opp et miljø for å skrive en REST API-tjeneste i C++ ved hjelp av docker/docker-compose og conan-pakkebehandlingen.
Under neste hackathon, der jeg deltok som backend-utvikler, dukket spørsmålet opp om hva jeg skulle bruke for å skrive neste mikrotjeneste. Alt som er skrevet så langt er skrevet av meg og min
Så vi sto overfor oppgaven med å skrive en høybelastningstjeneste, hvis hovedoppgave var å forhåndsbehandle dataene som kom til den og skrive dem til databasen. Og etter nok en røykpause, foreslo en venn at jeg som C++-utvikler skulle skrive denne tjenesten ved å bruke proffene. Dette argumenterer for at det vil være raskere, mer produktivt, og generelt sett vil juryen være fornøyd med hvordan vi vet hvordan vi skal forvalte teamets ressurser. Til det svarte jeg at jeg aldri hadde gjort slike ting i C++ og lett kunne bruke de resterende 20+ timene til å søke, kompilere og koble sammen passende biblioteker. Enkelt sagt, jeg chicken out. Det var det vi bestemte oss for og rolig fullførte alt i Python.
Nå, under den tvungne selvisolasjonen, bestemte jeg meg for å finne ut hvordan jeg skulle skrive tjenester i C++. Det første du måtte gjøre var å velge et passende bibliotek. Valget mitt falt på
conanfile.txt
[krever]poco/1.9.3
libpq/11.5
og med en enkel kommando "conan install ." installere de nødvendige bibliotekene. Det var naturligvis også nødvendig å gjøre endringer i
CMakeLists.txt
include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})
Etter det begynte jeg å se etter et bibliotek for å jobbe med PostgreSQL, siden det var det jeg hadde liten erfaring med å jobbe med, og det var også det som Python-tjenestene våre samhandlet med. Og vet du hva jeg lærte? Det er i POCO! Men conan vet ikke at den er i POCO og vet ikke hvordan den skal bygges; det er en utdatert konfigurasjonsfil i depotet (jeg har allerede skrevet om denne feilen til skaperne av POCO). Dette betyr at du må se etter et annet bibliotek.
Og så falt valget mitt på et mindre populært bibliotek
Neste steg var å skrive en tjenestemal som kan behandle forespørsler.
Vi må arve TemplateServerApp-klassen vår fra Poco::Util::ServerApplication og overstyre hovedmetoden.
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;
}
I hovedmetoden må vi angi parameterne: port, antall tråder og køstørrelse. Og viktigst av alt, du må spesifisere en behandler for innkommende forespørsler. Dette gjøres ved å lage en fabrikk
TemplateRequestHandlerFactory
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
{
return new TemplateServerAppHandler;
}
};
I mitt tilfelle skaper den ganske enkelt den samme behandleren hver gang - TemplateServerAppHandler. Det er her vi kan plassere forretningslogikken vår.
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();
}
};
Jeg har også laget en klassemal for å jobbe med PostgreSQL. For å utføre enkel SQL, som å lage en tabell, finnes det en metode ExecuteSQL(). For mer komplekse forespørsler eller datainnhenting må du få en tilkobling via GetConnection() og bruk libpg API. (Kanskje senere vil jeg rette opp denne urettferdigheten).
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;
};
Alle parametere for å koble til databasen er hentet fra miljøet, så du må også opprette og konfigurere .env-filen
.og V
DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432
Du kan se all koden på
Og nå kommer det siste stadiet med å skrive dockerfilen og docker-compose.yml. For å være ærlig tok dette mesteparten av tiden, og ikke bare fordi jeg er en noob, fordi det var nødvendig å gjenoppbygge bibliotekene hver gang, men på grunn av fallgruvene til conan. For eksempel, for at conan skal laste ned, installere og bygge de nødvendige avhengighetene, er det ikke nok for det å laste ned “conan install .”, det må også sende parameteren -s compiler.libcxx=libstdc++11, ellers du risikerer å få en haug med feil på koblingsstadiet din søknad. Jeg har sittet fast med denne feilen i flere timer, og jeg håper denne artikkelen vil hjelpe andre med å løse dette problemet på kortere tid.
Deretter, etter å ha skrevet docker-compose.yml, etter råd fra min venn, la jeg til støtte
Jeg håper denne malen vil hjelpe nybegynnere på deres vanskelige vei med å utvikle REST API-applikasjoner i det flotte og kraftige, men så klønete språket som C++.
Dessuten anbefaler jeg på det sterkeste å lese her
Kilde: www.habr.com