Webcc:基於 Asio 的 C++ REST 程序庫

2019/08/14:這篇文章已通過時了。Webcc 已經演化成了一個比較完備的純 HTTP 程序庫。
詳見:Webcc: 輕量級 C++ HTTP 程序庫git

Webcc 是我本身寫的一個 C++ Web Service 程序庫,網絡通訊基於 Boost Asio,跨平臺,輕量、高效。它並不是只是一個玩具,目前正應用於咱們實際的項目,並且還在不斷更新和完善。github

Webcc 同時支持客戶端和服務端,你能夠用它調用已經存在的 Web Service,也能夠用它實現本身的 Web Service,且同時支持 REST 和 SOAP 兩種方式。web

考慮到用 SOAP 的人愈來愈少,webcc 對 SOAP 的支持能夠經過宏 WEBCC_ENABLE_SOAP 在編譯時徹底剔除掉。正則表達式

Webcc 內部對 SOAP 消息的包裝和解析依賴於 PugiXml。若是禁掉 SOAP,PugiXml 天然也會一併禁掉;若是啓用 SOAP,但願你能承擔對 PugiXml 的這一份小小依賴。數據庫

對 SOAP 部分的介紹就這麼多,具體可見去年的這篇文章:C++ 調用 SOAP Web Servicesegmentfault

REST Server

假定你要提供一個關於圖書的 REST Server,提供下面這些操做或接口:網絡

  • 查詢圖書(基於某些特定的條件);
  • 添加一本新圖書;
  • 獲取一本圖書的詳細信息;
  • 更新一本圖書的信息;
  • 刪除一本圖書。

前面兩個操做能夠經過繼承 webcc::RestListService 來實現:框架

class BookListService : public webcc::RestListService {
 protected:
  // 查詢圖書(基於某些特定的條件)
  // GET /books?<query>
  bool Get(const webcc::UrlQuery& query,
           std::string* response_content) override;

  // 添加一本新圖書
  // POST /books
  // |request_content| 包含了新圖書的數據,爲 JSON 格式的字符串
  bool Post(const std::string& request_content,
            std::string* response_content) override;
};

其餘幾個操做,則須要繼承自 webcc::RestDetailServiceide

class BookDetailService : public webcc::RestDetailService {
 protected:
  // 獲取一本圖書的詳細信息
  bool Get(const std::vector<std::string>& url_sub_matches,
           const webcc::UrlQuery& query,
           std::string* response_content) override;

  // 更新一本圖書的信息
  bool Put(const std::vector<std::string>& url_sub_matches,
           const std::string& request_content,
           std::string* response_content) override;

  // 刪除一本圖書
  bool Delete(const std::vector<std::string>& url_sub_matches) override;
};

在 Python 的 Django 框架中,有幾種不一樣的視圖(View),其中 XxxListView 對應於一列對象,而 XxxDetailView 對應於單個對象。Webcc 的 RestListServiceRestDetailService 就是參考了 Django 的這一設計。url

對於 RestListService,URL 通常爲複數形式,好比 /books。對於 GET 請求,就是查詢對象,URL 通常會帶 query,好比 /books?author=Barnes;對於 POST 請求,就是建立新對象,信息由 HTTP 請求體攜帶,通常爲 JSON 格式。

對於 RestDetailService,URL 通常爲單數,好比 /book,而後還要指定對象的 ID,最終的 URL 格式爲 /book/{BookID},這個 ID 最終能夠經過 url_sub_matches 這個參數拿到。RestDetailService 支持 GET、PUT、PATCH 和 DELETE 幾種請求,分別對應於獲取、更新、部分更新和刪除。

下面看一下 BookDetailService::Get() 的實現:

bool BookDetailService::Get(const std::vector<std::string>& url_sub_matches,
                            const webcc::UrlQuery& query,
                            std::string* response_content) {
  if (url_sub_matches.size() != 1) {
    return false;
  }
  const std::string& book_id = url_sub_matches[0];

  // 接下來:
  // - 經過 book_id 從數據庫拿到這個圖書,
  // - 而後把圖書信息轉換成 JSON 格式的字符串,
  // - 最後把 JSON 字符串賦值給輸出參數 response_content。
}

Service 本身並不能運行,須要把它們綁定到 RestServer,下面是 main() 裏的部分代碼:

webcc::RestServer server(8080, 2);

server.Bind(std::make_shared<BookListService>(), "/books", false);
server.Bind(std::make_shared<BookDetailService>(), "/book/(\\d+)", true);

server.Run();

先建立一個 RestServer 對象,端口號爲 8080,後臺的工做線程數爲 2
而後分別建立 BookListServiceBookDetailService,都用 std::shared_ptr 來自動管理對象生命期。
最後綁定 services 到特定的 URL,其中 BookDetailService 的 URL 是一個正則表達式,(\\d+) 最後匹配下來的部分就存在參數 url_sub_matches 中。

相關文章
相關標籤/搜索