Mikrodienste in C++. Fiksie of werklikheid?

Mikrodienste in C++. Fiksie of werklikheid?

In hierdie artikel sal ek praat oor hoe ek 'n sjabloon (koekiesnyer) geskep het en 'n omgewing opstel vir die skryf van 'n REST API-diens in C++ met behulp van docker/docker-compose en die conan-pakketbestuurder.

Tydens die volgende hackathon, waaraan ek as 'n backend-ontwikkelaar deelgeneem het, het die vraag ontstaan ​​oor wat om te gebruik om die volgende mikrodiens te skryf. Alles wat tot dusver geskryf is, is deur my en my kameraad in Python, aangesien my kollega 'n kenner op hierdie gebied was en backends professioneel ontwikkel het, terwyl ek oor die algemeen 'n ingebedde stelselontwikkelaar was en in die wonderlike en verskriklike C++ geskryf het, en ek het pas Python op universiteit geleer.

Ons het dus voor die taak gestaan ​​om 'n hoëladingdiens te skryf, waarvan die hooftaak was om die data wat daarheen kom vooraf te verwerk en dit na die databasis te skryf. En na nog 'n rookpouse het 'n vriend voorgestel dat ek, as 'n C++-ontwikkelaar, hierdie diens met die voordele skryf. Om dit te argumenteer is dat dit vinniger, meer produktief sal wees, en in die algemeen sal die jurie verheug wees oor hoe ons weet hoe om die span se hulpbronne te bestuur. Waarop ek geantwoord het dat ek nog nooit sulke goed in C++ gedoen het nie en maklik die oorblywende 20+ ure kon afstaan ​​aan die soek, saamstel en koppel van geskikte biblioteke. Eenvoudig gestel, ek het gekuier. Dit is waarop ons besluit het en alles rustig in Python voltooi het.

Nou, tydens die gedwonge self-isolasie, het ek besluit om uit te vind hoe om dienste in C++ te skryf. Die eerste ding om te doen was om op 'n geskikte biblioteek te besluit. My keuse het geval POCO, aangesien dit in 'n objekgeoriënteerde styl geskryf is en ook met normale dokumentasie gespog het. Die vraag het ook ontstaan ​​oor die keuse van 'n monteerstelsel. Tot op hierdie stadium het ek net met Visual Studio, IAR en blote make-lêers gewerk. En nie een van hierdie stelsels het my aangespreek nie, aangesien ek beplan het om die hele diens in 'n dokhouer te laat loop. Toe besluit ek om cmake en 'n interessante pakketbestuurder te probeer uitvind Conan. Hierdie pakketbestuurder het jou toegelaat om alle afhanklikhede in een lêer te registreer

conanfile.txt
[vereis]poco/1.9.3
libpq/11.5

[generators] cmake

en met 'n eenvoudige opdrag "conan install ." installeer die nodige biblioteke. Dit was natuurlik ook nodig om veranderinge aan te bring

CMakeLists.txt

include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})

Daarna het ek begin soek na 'n biblioteek om met PostgreSQL te werk, aangesien dit die een was waarmee ek min ervaring gehad het, en dit was ook die een waarmee ons Python-dienste in wisselwerking was. En weet jy wat ek geleer het? Dit is in POCO! Maar conan weet nie dat dit in POCO is nie en weet nie hoe om dit te bou nie; daar is 'n verouderde konfigurasielêer in die bewaarplek (ek het reeds oor hierdie fout aan die skeppers van POCO geskryf). Dit beteken jy sal na 'n ander biblioteek moet soek.

En toe val my keuse op 'n minder gewilde biblioteek libpg. En ek was ongelooflik gelukkig, dit was reeds in conan en was selfs aanmekaargesit en aanmekaargesit.

Die volgende stap was om 'n dienssjabloon te skryf wat versoeke kan verwerk.
Ons moet ons TemplateServerApp-klas van Poco::Util::ServerApplication erf en die hoofmetode ignoreer.

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;
}

In die hoofmetode moet ons die parameters stel: poort, aantal drade en tougrootte. En die belangrikste, jy moet 'n hanteerder spesifiseer vir inkomende versoeke. Dit word gedoen deur 'n fabriek te skep

TemplateRequestHandlerFactory

class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
    {
        return new TemplateServerAppHandler;
    }
};

In my geval skep dit eenvoudig elke keer dieselfde hanteerder - TemplateServerAppHandler. Dit is waar ons ons besigheidslogika kan plaas.

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();
    }
};

Ek het ook 'n klassjabloon geskep om met PostgreSQL te werk. Om eenvoudige SQL uit te voer, soos om 'n tabel te skep, is daar 'n metode VoerSQL() uit. Vir meer komplekse navrae of dataherwinning, sal jy 'n verbinding via GetConnection() en gebruik die libpg API. (Miskien sal ek later hierdie onreg regstel).

Databasis

#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 parameters om aan die databasis te koppel word uit die omgewing geneem, so jy moet ook die .env-lêer skep en konfigureer

.a V

DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432

Jy kan al die kode sien by github.

Mikrodienste in C++. Fiksie of werklikheid?

En nou kom die finale stadium van die skryf van die dockerfile en docker-compose.yml. Om eerlik te wees, dit het die meeste van die tyd geneem, en nie net omdat ek 'n noob is nie, omdat dit nodig was om die biblioteke elke keer te herbou, maar as gevolg van die slaggate van conan. Om byvoorbeeld vir conan die nodige afhanklikhede af te laai, te installeer en te bou, is dit nie genoeg om “conan install .” af te laai nie, dit moet ook die parameter -s compiler.libcxx=libstdc++11 slaag, anders jy loop die risiko om 'n klomp foute te kry tydens die koppeling van jou aansoek. Ek sit al vir 'n paar uur met hierdie fout en ek hoop dat hierdie artikel ander mense sal help om hierdie probleem in minder tyd op te los.

Vervolgens, nadat ek docker-compose.yml geskryf het, op advies van my vriend, het ek ondersteuning bygevoeg koekiedrukker en nou kan jy vir jou 'n volwaardige sjabloon vir 'n REST API-diens in C++ kry, met 'n pasgemaakte omgewing, en PostgreSQL geïnstalleer, eenvoudig deur "koekiesnyer" in die konsole in te voer https://github.com/KovalevVasiliy/cpp_rest_api_template.git" En dan "doker-compose up -bou".

Ek hoop dat hierdie sjabloon beginners sal help op hul moeilike pad om REST API-toepassings te ontwikkel in die wonderlike en kragtige, maar so 'n lomp taal soos C++.
Ek beveel ook sterk aan om hier te lees hierdie artikel. Dit verduidelik in meer besonderhede hoe om met POCO te werk en jou eie REST API-diens te skryf.

Bron: will.com

Voeg 'n opmerking