У овом чланку ћу говорити о томе како сам направио шаблон (цоокиецуттер) и подесио окружење за писање РЕСТ АПИ услуге у Ц++ користећи доцкер/доцкер-цомпосе и цонан менаџер пакета.
Током следећег хакатона, у коме сам учествовао као бацкенд девелопер, поставило се питање шта користити за писање следећег микросервиса. Све што је до сада написано написали смо ја и моји
Дакле, били смо суочени са задатком да напишемо сервис са великим оптерећењем, чији је главни задатак био да претходно обради податке који су му пристизали и упише их у базу података. И после још једне паузе за дим, пријатељ ми је предложио да ја, као Ц++ програмер, напишем ову услугу користећи професионалце. Тврди се да ће то бити брже, продуктивније и генерално, жири ће бити одушевљен како знамо да управљамо ресурсима тима. На шта сам одговорио да никада нисам радио такве ствари у Ц++-у и да бих лако могао да посветим преосталих 20+ сати тражењу, компајлирању и повезивању одговарајућих библиотека. Једноставно речено, одлепио сам. То је оно за шта смо се одлучили и мирно завршили све у Питхон-у.
Сада, током принудне самоизолације, одлучио сам да смислим како да напишем сервисе у Ц++. Прво је требало да се одлучи за одговарајућу библиотеку. Мој избор је пао
цонанфиле.ткт
[захтева]поцо/1.9.3
либпк/11.5
и једноставном командом "цонан инсталл ." инсталирати потребне библиотеке. Наравно, било је потребно и измене у
ЦМакеЛистс.ткт
include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})
Након тога, почео сам да тражим библиотеку за рад са ПостгреСКЛ-ом, пошто је то била она са којом сам имао мало искуства у раду, а такође је била и она са којом су наши Питхон сервиси комуницирали. И знате ли шта сам научио? У ПОЦО је! Али Цонан не зна да је у ПОЦО-у и не зна како да га направи; у спремишту постоји застарела конфигурациона датотека (већ сам писао о овој грешци креаторима ПОЦО-а). То значи да ћете морати да потражите другу библиотеку.
А онда је мој избор пао на мање популарну библиотеку
Следећи корак је био писање шаблона услуге који може да обрађује захтеве.
Морамо наследити нашу ТемплатеСерверАпп класу од Поцо::Утил::СерверАпплицатион и заменити главни метод.
ТемплатеСерверАпп
#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;
}
У главном методу морамо подесити параметре: порт, број нити и величину реда. И што је најважније, морате навести руковаоца за долазне захтеве. Ово се ради стварањем фабрике
ТемплатеРекуестХандлерФацтори
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
{
return new 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();
}
};
Такође сам направио шаблон класе за рад са ПостгреСКЛ-ом. За извођење једноставног СКЛ-а, као што је креирање табеле, постоји метод ЕкецутеСКЛ(). За сложеније упите или преузимање података, мораћете да успоставите везу преко ГетЦоннецтион() и користите либпг АПИ. (Можда ћу касније исправити ову неправду).
База података
#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;
};
Сви параметри за повезивање са базом података преузети су из окружења, тако да је потребно да креирате и конфигуришете .енв датотеку
.енв
DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432
Можете видети сав код на
И сада долази последња фаза писања доцкерфиле-а и доцкер-цомпосе.имл. Да будем искрен, ово је одузело већину времена, и то не само зато што сам нооб, јер је сваки пут било потребно обнављати библиотеке, већ и због замки Конана. На пример, да би цонан преузео, инсталирао и изградио потребне зависности, није довољно да преузме „цонан инсталл .“, већ треба и да проследи параметар -с цомпилер.либцкк=либстдц++11, у супротном ризикујете да добијете гомилу грешака у фази повезивања ваше апликације. Заглавио сам са овом грешком неколико сати и надам се да ће овај чланак помоћи другим људима да реше овај проблем за краће време.
Затим, након што сам написао доцкер-цомпосе.имл, по савету мог пријатеља, додао сам подршку
Надам се да ће овај шаблон помоћи почетницима на њиховом тешком путу развоја РЕСТ АПИ апликација на сјајном и моћном, али тако незграпном језику као што је Ц++.
Такође, топло препоручујем читање овде
Извор: ввв.хабр.цом