Sa artikulong ito ay pag-uusapan ko kung paano ako gumawa ng template (cookiecutter) at nag-set up ng environment para sa pagsusulat ng REST API service sa C++ gamit ang docker/docker-compose at ang conan package manager.
Sa susunod na hackathon, kung saan lumahok ako bilang isang backend developer, bumangon ang tanong tungkol sa kung ano ang gagamitin para isulat ang susunod na microservice. Lahat ng naisulat sa ngayon ay isinulat ko at ng aking
Kaya, nahaharap kami sa gawain ng pagsulat ng isang serbisyong may mataas na pagkarga, ang pangunahing gawain kung saan ay i-preprocess ang data na dumarating dito at isulat ito sa database. At pagkatapos ng isa pang smoke break, iminungkahi ng isang kaibigan na ako, bilang isang developer ng C++, ay isulat ang serbisyong ito gamit ang mga pro. Ang pangangatwiran nito ay magiging mas mabilis, mas produktibo, at sa pangkalahatan, matutuwa ang hurado sa kung paano natin malalaman kung paano pamahalaan ang mga mapagkukunan ng koponan. Kung saan sumagot ako na hindi ko pa nagawa ang mga ganoong bagay sa C++ at madaling italaga ang natitirang 20+ na oras sa paghahanap, pag-compile at pag-link ng mga angkop na aklatan. Sa madaling salita, nag-chick out ako. Iyon ang napagpasyahan namin at mahinahong natapos ang lahat sa Python.
Ngayon, sa panahon ng sapilitang pag-iisa sa sarili, nagpasya akong malaman kung paano magsulat ng mga serbisyo sa C++. Ang unang bagay na dapat gawin ay magpasya sa isang angkop na aklatan. Ang aking pinili ay nahulog sa
conanfile.txt
[nangangailangan]poco/1.9.3
libpq/11.5
at may simpleng command na "conan install ." i-install ang mga kinakailangang aklatan. Natural, kailangan ding gumawa ng mga pagbabago sa
CMakeLists.txt
include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})
Pagkatapos noon, nagsimula akong maghanap ng library para magtrabaho sa PostgreSQL, dahil ito ang kakaunting karanasan ko sa pagtatrabaho, at ito rin ang nakipag-ugnayan sa aming mga serbisyo sa Python. At alam mo ba kung ano ang natutunan ko? Ito ay nasa POCO! Ngunit hindi alam ni conan na ito ay nasa POCO at hindi alam kung paano ito itatayo; mayroong isang hindi napapanahong configuration file sa repositoryo (naisulat ko na ang tungkol sa error na ito sa mga tagalikha ng POCO). Nangangahulugan ito na kailangan mong maghanap ng isa pang aklatan.
At pagkatapos ay nahulog ang aking pinili sa isang hindi gaanong sikat na library
Ang susunod na hakbang ay ang pagsulat ng template ng serbisyo na maaaring magproseso ng mga kahilingan.
Dapat nating mamana ang aming klase ng TemplateServerApp mula sa Poco::Util::ServerApplication at i-override ang pangunahing paraan.
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;
}
Sa pangunahing paraan dapat nating itakda ang mga parameter: port, bilang ng mga thread at laki ng pila. At higit sa lahat, kailangan mong tukuyin ang isang handler para sa mga papasok na kahilingan. Ginagawa ito sa pamamagitan ng paglikha ng isang pabrika
TemplateRequestHandlerFactory
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
{
return new TemplateServerAppHandler;
}
};
Sa aking kaso, lumilikha lamang ito ng parehong handler sa bawat oras - TemplateServerAppHandler. Dito natin mailalagay ang lohika ng ating negosyo.
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();
}
};
Gumawa din ako ng template ng klase upang gumana sa PostgreSQL. Upang maisagawa ang simpleng SQL, tulad ng paglikha ng isang talahanayan, mayroong isang paraan ExecuteSQL(). Para sa mas kumplikadong mga query o data retrieval, kakailanganin mong kumuha ng koneksyon sa pamamagitan ng GetConnection() at gamitin ang libpg API. (Marahil mamaya ay itatama ko itong kawalang-katarungan).
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;
};
Ang lahat ng mga parameter para sa pagkonekta sa database ay kinuha mula sa kapaligiran, kaya kailangan mo ring lumikha at i-configure ang .env file
.env
DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432
Makikita mo ang lahat ng code sa
At ngayon ay darating ang huling yugto ng pagsulat ng dockerfile at docker-compose.yml. Sa totoo lang, madalas itong tumagal, at hindi lamang dahil ako ay isang noob, dahil kinakailangan na muling itayo ang mga aklatan sa bawat oras, ngunit dahil sa mga pitfalls ng conan. Halimbawa, upang mai-download, mai-install at mabuo ni conan ang mga kinakailangang dependency, hindi sapat na i-download nito ang βconan install .β, kailangan din nitong ipasa ang -s compiler.libcxx=libstdc++11 na parameter, kung hindi. nanganganib kang makakuha ng maraming error sa yugto ng pagli-link ng iyong aplikasyon. Ilang oras na akong natigil sa error na ito at umaasa akong makakatulong ang artikulong ito sa ibang tao na malutas ang problemang ito sa mas kaunting oras.
Susunod, pagkatapos magsulat ng docker-compose.yml, sa payo ng aking kaibigan, nagdagdag ako ng suporta
Umaasa ako na ang template na ito ay makakatulong sa mga nagsisimula sa kanilang mahirap na landas ng pagbuo ng mga REST API application sa mahusay at makapangyarihan, ngunit tulad ng isang clumsy na wika tulad ng C++.
Gayundin, lubos kong inirerekumenda ang pagbabasa dito
Pinagmulan: www.habr.com