Në këtë artikull do të flas se si kam krijuar një shabllon (cookiecutter) dhe kam vendosur një mjedis për të shkruar një shërbim REST API në C++ duke përdorur docker/docker-compose dhe menaxherin e paketave conan.
Gjatë hackathon-it të ardhshëm, në të cilin mora pjesë si zhvillues i backend-it, lindi pyetja se çfarë të përdorja për të shkruar mikroshërbimin e ardhshëm. Gjithçka që është shkruar deri tani është shkruar nga unë dhe imja
Pra, ne u përballëm me detyrën e shkrimit të një shërbimi me ngarkesë të lartë, detyra kryesore e të cilit ishte të përpunonte paraprakisht të dhënat që vinin tek ai dhe t'i shkruante ato në bazën e të dhënave. Dhe pas një pushimi tjetër tymi, një mik sugjeroi që unë, si zhvillues i C++, ta shkruaj këtë shërbim duke përdorur profesionistët. Argumentimi për këtë është se do të jetë më i shpejtë, më produktiv dhe në përgjithësi, juria do të jetë e kënaqur me mënyrën se si ne dimë të menaxhojmë burimet e ekipit. Për të cilën unë u përgjigja se nuk kisha bërë kurrë gjëra të tilla në C++ dhe mund t'i kushtoja lehtësisht 20+ orët e mbetura kërkimit, përpilimit dhe lidhjes së bibliotekave të përshtatshme. Ta themi thjesht, u largova. Kjo është ajo që vendosëm dhe përfunduam me qetësi gjithçka në Python.
Tani, gjatë izolimit të detyruar, vendosa të kuptoj se si të shkruaj shërbimet në C++. Gjëja e parë që duhet bërë ishte të vendosni për një bibliotekë të përshtatshme. Zgjedhja ime ra
conanfile.txt
[kërkon]
poco/1.9.3
libpq/11.5
dhe me një komandë të thjeshtë "conan install ." instaloni bibliotekat e nevojshme. Natyrisht, ishte gjithashtu e nevojshme të bëhen ndryshime në
CMakeLists.txt
include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})
Pas kësaj, fillova të kërkoja një bibliotekë për të punuar me PostgreSQL, pasi ishte biblioteka me të cilën kisha pak përvojë pune, dhe ishte gjithashtu ajo me të cilën ndërvepruan shërbimet tona Python. Dhe a e dini se çfarë mësova? Është në POCO! Por Conan nuk e di që është në POCO dhe nuk di se si ta ndërtojë; ekziston një skedar konfigurimi i vjetëruar në depo (u kam shkruar tashmë për këtë gabim krijuesve të POCO). Kjo do të thotë që ju do të duhet të kërkoni për një bibliotekë tjetër.
Dhe pastaj zgjedhja ime ra në një bibliotekë më pak të njohur
Hapi tjetër ishte të shkruani një model shërbimi që mund të përpunojë kërkesat.
Ne duhet të trashëgojmë klasën tonë TemplateServerApp nga Poco::Util::ServerApplication dhe të anashkalojmë metodën kryesore.
TemplateServer App
#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;
}
Në metodën kryesore duhet të vendosim parametrat: portin, numrin e thread-eve dhe madhësinë e radhës. Dhe më e rëndësishmja, duhet të specifikoni një mbajtës për kërkesat hyrëse. Kjo bëhet duke krijuar një fabrikë
TemplateRequestHandlerFactory
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
{
return new TemplateServerAppHandler;
}
};
Në rastin tim, ai thjesht krijon të njëjtin mbajtës çdo herë - TemplateServerAppHandler. Këtu mund të vendosim logjikën tonë të biznesit.
TemplateServerApp Handler
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();
}
};
Krijova gjithashtu një shabllon klase për të punuar me PostgreSQL. Për të kryer SQL të thjeshtë, siç është krijimi i një tabele, ekziston një metodë ExecuteSQL(). Për pyetje më komplekse ose rikthim të të dhënave, do t'ju duhet të merrni një lidhje nëpërmjet GetConnection () dhe përdorni API-në libpg. (Ndoshta më vonë do ta korrigjoj këtë padrejtësi).
Baza e të dhënave
#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;
};
Të gjithë parametrat për lidhjen me bazën e të dhënave janë marrë nga mjedisi, kështu që ju gjithashtu duhet të krijoni dhe konfiguroni skedarin .env
.zili
DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432
Ju mund të shihni të gjithë kodin në
Dhe tani vjen faza e fundit e shkrimit të dockerfile dhe docker-compose.yml. Për të qenë i sinqertë, kjo mori pjesën më të madhe të kohës, dhe jo vetëm sepse unë jam noob, sepse ishte e nevojshme të rindërtonim bibliotekat çdo herë, por për shkak të grackave të Conan. Për shembull, në mënyrë që conan të shkarkojë, instalojë dhe të ndërtojë varësitë e nevojshme, nuk mjafton që ai të shkarkojë "conan install .", ai gjithashtu duhet të kalojë parametrin -s compiler.libcxx=libstdc++11, përndryshe rrezikoni të merrni një sërë gabimesh në fazën e lidhjes së aplikacionit tuaj. Unë kam ngecur me këtë gabim për disa orë dhe shpresoj se ky artikull do t'i ndihmojë njerëzit e tjerë ta zgjidhin këtë problem në më pak kohë.
Më pas, pasi shkruajta docker-compose.yml, me këshillën e mikut tim, shtova mbështetje
Shpresoj se ky shabllon do t'i ndihmojë fillestarët në rrugën e tyre të vështirë të zhvillimit të aplikacioneve REST API në gjuhën e madhe dhe të fuqishme, por një gjuhë kaq të ngathët si C++.
Gjithashtu, unë rekomandoj shumë të lexoni këtu
Burimi: www.habr.com