在本文中,我將討論如何建立範本 (cookiecutter) 並設定環境,以便使用 docker/docker-compose 和 conan 套件管理器在 C++ 中編寫 REST API 服務。
在我作為後端開發人員參加的下一次黑客馬拉松中,出現了關於使用什麼來編寫下一個微服務的問題。到目前為止所寫的所有內容都是我和我的朋友寫的
因此,我們面臨著編寫高負載服務的任務,其主要任務是預處理傳入的資料並將其寫入資料庫。在又一次冒煙之後,一位朋友建議我,作為一名 C++ 開發人員,使用專業人士來編寫此服務。我認為這樣做會更快、更有效率,而且總的來說,評審團會對我們如何管理團隊資源感到高興。我回答說我從來沒有在 C++ 中做過這樣的事情,並且可以輕鬆地將剩餘的 20 多個小時用於搜尋、編譯和連結合適的程式庫。簡單地說,我退縮了。我們就這樣決定了,並平靜地用Python完成了一切。
現在,在強制自我隔離期間,我決定弄清楚如何用 C++ 編寫服務。要做的第一件事是決定一個合適的函式庫。我的選擇落到了
柯南文件.txt
[requires]
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!但柯南不知道它在 POCO 中,也不知道如何構建它;存儲庫中有一個過時的配置文件(我已經向 POCO 的創建者寫了有關此錯誤的信息)。這意味著您將不得不尋找另一個圖書館。
然後我選擇了一個不太受歡迎的圖書館
下一步是編寫一個可以處理請求的服務模板。
我們必須從 Poco::Util::ServerApplication 繼承 TemplateServerApp 類別並重寫 main 方法。
模板伺服器應用程式
#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;
}
在main方法中我們必須設定參數:連接埠、執行緒數和佇列大小。最重要的是,您必須為傳入請求指定一個處理程序。這是透過創建工廠來完成的
模板請求處理工廠
class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
{
return new 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,例如建立表,有一個方法 執行SQL()。對於更複雜的查詢或資料檢索,您必須透過以下方式取得連接 取得連線() 並使用 libpg API。 (也許以後我會糾正這個不公平的現象)。
數據庫
#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後,根據朋友的建議,我添加了支持
我希望這個模板能夠幫助初學者走上使用 C++ 這樣強大但笨拙的語言開發 REST API 應用程式的艱難道路。
另外,我強烈推薦在這裡閱讀
來源: www.habr.com