Örþjónusta í C++. Skáldskapur eða raunveruleiki?

Örþjónusta í C++. Skáldskapur eða raunveruleiki?

Í þessari grein mun ég tala um hvernig ég bjó til sniðmát (kökuskera) og setti upp umhverfi til að skrifa REST API þjónustu í C ++ með því að nota docker / docker-compose og conan pakkastjórann.

Á næsta hackathon, þar sem ég tók þátt sem bakendi verktaki, vaknaði spurningin um hvernig ætti að skrifa næstu örþjónustu. Allt sem hefur verið skrifað hingað til hefur verið skrifað af mér og mínum félagi í Python tungumálinu, þar sem kollegi minn var sérfræðingur á þessu sviði og faglega þróað bakenda, á meðan ég var almennt innbyggður kerfisframleiðandi og skrifaði á hinu frábæra og hræðilega C++, og Python lærði bara í háskólanum.

Þannig að við stóðum frammi fyrir því verkefni að skrifa mjög hlaðna þjónustu, aðalverkefni hennar var að forvinna gögnin sem komu til hennar og skrifa þau í gagnagrunninn. Og eftir annað reykhlé stakk vinur vinur upp á að sem C++ verktaki myndi ég skrifa þessa þjónustu á plús-merkjunum. Með því að halda því fram að það verði hraðari, afkastameiri og almennt mun dómnefndin vera ánægð með hvernig við vitum hvernig á að stjórna auðlindum liðsins. Því svaraði ég að ég hefði aldrei gert slíka hluti í C++ og gæti auðveldlega varið þeim 20+ klukkustundum sem eftir eru í að finna, setja saman og tengja saman viðeigandi bókasöfn. Einfaldlega sagt, ég kjúklingur út. Á það ákváðu þeir og bættu öllu rólega við í Python.

Nú, við þvingaða sjálfeinangrun, ákvað ég að finna út hvernig á að skrifa þjónustu í C ++. Það fyrsta sem þurfti að gera var að ákveða viðeigandi bókasafn. Val mitt féll á POCO, þar sem það var skrifað í hlutbundnum stíl og státaði einnig af eðlilegum skjölum. Einnig vaknaði spurningin um val á byggingarkerfinu. Hingað til hef ég aðeins unnið með Visual Studio, IAR og berum makefile. Og ekkert af þessum kerfum höfðaði til mín, þar sem ég ætlaði að keyra alla þjónustuna í hafnargámi. Svo ákvað ég að reyna að takast á við cmake og áhugaverðan pakkastjóra conan. Þessi pakkastjóri gerði þér kleift að skrifa allar ósjálfstæðin í eina skrá

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

[rafallar] cmake

og með einfaldri skipun "conan install ." setja upp nauðsynleg bókasöfn. Auðvitað var líka nauðsynlegt að gera breytingar á

CMakeLists.txt

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

Eftir það fór ég að leita að bókasafni til að vinna með PostgreSQL, þar sem það var með það sem ég hafði litla reynslu, og það var líka með það sem Python þjónusturnar okkar höfðu samskipti. Og veistu hvað ég komst að? Hún er í POCO! En conan veit ekki að það er í POCO og veit ekki hvernig á að byggja það, geymslan inniheldur úrelta stillingarskrá (ég skrifaði nú þegar um þessa villu til höfunda POCO). Svo þú verður að leita að öðru bókasafni.

Og þá féll val mitt á minna vinsælt bókasafn libpg. Og ég var ótrúlega heppin, hún var þegar í conan og meira að segja sett saman og sett saman.

Næsta skref var að skrifa þjónustusniðmát sem getur unnið úr beiðnum.
Við verðum að fá TemplateServerApp flokkinn okkar frá Poco::Util::ServerApplication og hnekkja aðalaðferðinni.

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

Í aðalaðferðinni verðum við að stilla færibreyturnar: höfn, fjölda þráða og biðraðarstærð. Og síðast en ekki síst, þú verður að stilla umsjónarmanninn fyrir komandi beiðnir. Þetta er gert með því að búa til verksmiðju

TemplateRequestHandlerFactory

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

Í mínu tilviki býr það bara til sama stjórnandann í hvert skipti - TemplateServerAppHandler. Þetta er þar sem við getum sett viðskiptarökfræði okkar.

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

Ég bjó líka til bekkjarsniðmát til að vinna með PostgreSQL. Til þess að framkvæma einfalda SQL, eins og að búa til töflu, er til aðferð KeyraSQL(). Fyrir flóknari fyrirspurnir eða að fá gögn verður þú að fá tenginguna í gegnum GetConnection() og notaðu libpg API. (Kannski mun ég leiðrétta þetta óréttlæti síðar).

Gagnasafn

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

Allar breytur til að tengjast gagnagrunninum eru teknar úr umhverfinu, svo þú þarft líka að búa til og stilla .env skrána

.NS

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

Þú getur séð allan kóðann á github.

Örþjónusta í C++. Skáldskapur eða raunveruleiki?

Og síðasti áfanginn við að skrifa dockerfile og docker-compose.yml er kominn. Satt að segja tók þetta mestan tíma, og ekki bara vegna þess að ég er noob, að það hafi verið nauðsynlegt að endurbyggja bókasöfnin í hvert skipti, heldur vegna gildra conan. Svo til dæmis, til þess að conan geti hlaðið niður, sett upp og byggt upp nauðsynlegar ósjálfstæði, þá er ekki nóg fyrir hann að hala niður „conan install . annars er hætta á að þú fáir fullt af villum á tengistigi umsóknarinnar þinnar. Ég hef verið fastur með þessa villu í nokkrar klukkustundir og ég vona að þessi grein muni hjálpa öðrum að leysa þetta vandamál á styttri tíma.

Ennfremur, eftir að hafa skrifað docker-compose.yml, að ráði vinar míns, bætti ég við stuðningi við köku skerari og nú geturðu fengið þér fullbúið sniðmát fyrir REST API þjónustu í C ++, með stilltu umhverfi og hækkuðu PostgreSQL, einfaldlega með því að slá inn „kökuskera“ í stjórnborðið https://github.com/KovalevVasiliy/cpp_rest_api_template.git". Og svo "docker-compose up --build".

Ég vona að þetta sniðmát muni hjálpa byrjendum á erfiðri leið sinni við að þróa REST API forrit á hinu frábæra og öfluga, en svo klaufalega tungumáli eins og C ++.
Einnig mæli ég eindregið með því að lesa hér þetta grein. Það útskýrir nánar hvernig á að vinna með POCO og skrifa þína eigin REST API þjónustu.

Heimild: www.habr.com

Bæta við athugasemd