Այս հոդվածում ես կխոսեմ այն մասին, թե ինչպես ստեղծեցի ձևանմուշ (cookiecutter) և ստեղծեցի միջավայր C++-ում REST API ծառայություն գրելու համար՝ օգտագործելով docker/docker-compose և conan փաթեթի կառավարիչը։
Հաջորդ հաքաթոնի ժամանակ, որին ես մասնակցում էի որպես backend-ի ծրագրավորող, հարց առաջացավ, թե ինչ օգտագործել հաջորդ միկրոսերվիսը գրելու համար։ Այն ամենը, ինչ գրվել է մինչ այժմ, գրել ենք իմ և իմ կողմից
Այսպիսով, մեր առջեւ խնդիր էր դրված գրել մեծ բեռնված ծառայություն, որի հիմնական խնդիրն էր նախապես մշակել դրան եկող տվյալները եւ գրել դրանք տվյալների բազայում։ Եվ հերթական ծխի ընդմիջումից հետո ընկերս առաջարկեց, որ ես՝ որպես C++ ծրագրավորող, գրեմ այս ծառայությունը՝ օգտագործելով պրոֆեսիոնալները։ Պնդելով սա այն է, որ դա կլինի ավելի արագ, ավելի արդյունավետ, և, ընդհանուր առմամբ, ժյուրին հիացած կլինի նրանով, թե ինչպես մենք գիտենք, թե ինչպես կառավարել թիմի ռեսուրսները: Ինչին ես պատասխանեցի, որ ես երբեք նման բաներ չեմ արել C++-ում և կարող եմ հեշտությամբ տրամադրել մնացած 20+ ժամերը համապատասխան գրադարաններ փնտրելու, կազմելու և կապելու համար: Պարզ ասած, ես դուրս եկա: Դա այն է, ինչ մենք որոշեցինք և հանգիստ ավարտեցինք ամեն ինչ Python-ում:
Հիմա, հարկադիր ինքնամեկուսացման ժամանակ, ես որոշեցի պարզել, թե ինչպես գրել ծառայություններ C++-ով: Առաջին բանը, որ պետք է անել, համապատասխան գրադարանի որոշումն էր: Իմ ընտրությունը ընկավ
conanfile.txt
[պահանջում է] poco/1.9.3
libpq/11.5
և պարզ հրամանով «conan install »: տեղադրել անհրաժեշտ գրադարանները: Բնականաբար, անհրաժեշտ էր նաև փոփոխություններ կատարել
CMakeLists.txt
include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})
Դրանից հետո ես սկսեցի գրադարան փնտրել PostgreSQL-ի հետ աշխատելու համար, քանի որ դա այն գրադարանն էր, որի հետ աշխատելու քիչ փորձ ունեի, և դա այն գրադարանն էր, որի հետ համագործակցում էին մեր Python ծառայությունները: Իսկ դուք գիտե՞ք, թե ինչ եմ սովորել։ Այն գտնվում է POCO-ում: Բայց Conan-ը չգիտի, որ այն գտնվում է POCO-ում և չգիտի, թե ինչպես կառուցել այն, պահեստում կա հնացած կազմաձևման ֆայլ (ես արդեն գրել եմ այս սխալի մասին POCO-ի ստեղծողներին): Սա նշանակում է, որ դուք պետք է փնտրեք այլ գրադարան:
Եվ հետո իմ ընտրությունը ընկավ ոչ այնքան հայտնի գրադարանի վրա
Հաջորդ քայլը ծառայության ձևանմուշ գրելն էր, որը կարող է մշակել հարցումները:
Մենք պետք է ժառանգենք մեր TemplateServerApp դասը Poco::Util::ServerApplication-ից և անտեսենք հիմնական մեթոդը:
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;
}
Հիմնական մեթոդում մենք պետք է սահմանենք պարամետրերը՝ պորտ, թելերի քանակը և հերթի չափը։ Եվ ամենակարևորը, դուք պետք է նշեք մուտքային հարցումների մշակող: Դա արվում է գործարան ստեղծելով
TemplateRequestHandlerFactory
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
{
return new TemplateServerAppHandler;
}
};
Իմ դեպքում, այն պարզապես ամեն անգամ ստեղծում է նույն մշակիչը՝ TemplateServerAppHandler: Այստեղ մենք կարող ենք տեղադրել մեր բիզնես տրամաբանությունը:
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();
}
};
Ես նաև ստեղծել եմ դասի ձևանմուշ՝ PostgreSQL-ի հետ աշխատելու համար: Պարզ SQL-ի կատարման համար, օրինակ՝ աղյուսակ ստեղծելու համար, կա մեթոդ ExecuteSQL (). Ավելի բարդ հարցումների կամ տվյալների որոնման համար դուք պետք է կապ ձեռք բերեք միջոցով GetConnection () և օգտագործեք libpg API-ն: (Երևի հետո ես ուղղեմ այս անարդարությունը)։
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;
};
Տվյալների բազայի հետ միանալու բոլոր պարամետրերը վերցված են միջավայրից, այնպես որ դուք նույնպես պետք է ստեղծեք և կարգավորեք .env ֆայլը:
.env
DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432
Դուք կարող եք տեսնել ամբողջ ծածկագիրը այստեղ
Եվ հիմա գալիս է dockerfile-ը և docker-compose.yml-ը գրելու վերջին փուլը: Անկեղծ ասած, դա խլեց ժամանակի մեծ մասը, և ոչ միայն այն պատճառով, որ ես նոբիկ եմ, որովհետև անհրաժեշտ էր ամեն անգամ վերակառուցել գրադարանները, այլ Կոնանի որոգայթների պատճառով: Օրինակ, որպեսզի conan-ը ներբեռնի, տեղադրի և կառուցի անհրաժեշտ կախվածությունները, բավական չէ, որ նա ներբեռնի «conan install .»-ը, այն նաև պետք է անցնի -s compiler.libcxx=libstdc++11 պարամետրը, այլապես։ Դուք վտանգում եք ստանալ մի շարք սխալներ ձեր դիմումի կապակցման փուլում: Ես խրված եմ այս սխալի հետ մի քանի ժամով, և հուսով եմ, որ այս հոդվածը կօգնի այլ մարդկանց լուծել այս խնդիրը ավելի քիչ ժամանակում:
Հաջորդը, docker-compose.yml-ը գրելուց հետո, ընկերոջս խորհրդով, ավելացրի աջակցություն
Հուսով եմ, որ այս ձևանմուշը կօգնի սկսնակներին REST API հավելվածների զարգացման դժվարին ճանապարհին մեծ և հզոր, բայց այնպիսի անշնորհք լեզվով, ինչպիսին C++-ն է:
Բացի այդ, ես բարձր խորհուրդ եմ տալիս կարդալ այստեղ
Source: www.habr.com