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 中。

相关文章
相关标签/搜索