LCOV - code coverage report
Current view: top level - http/client - client.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 97.1 % 35 34
Test Date: 2026-04-21 17:49:55 Functions: 95.5 % 22 21

            Line data    Source code
       1              : #ifndef THINGER_HTTP_CLIENT_STANDALONE_HPP
       2              : #define THINGER_HTTP_CLIENT_STANDALONE_HPP
       3              : 
       4              : #include "http_client_base.hpp"
       5              : #include "request_builder.hpp"
       6              : #include <boost/asio/io_context.hpp>
       7              : 
       8              : namespace thinger::http {
       9              : 
      10              : /**
      11              :  * Standalone HTTP client with simple synchronous API.
      12              :  * Perfect for scripts, CLI tools, and simple applications.
      13              :  *
      14              :  * Usage:
      15              :  *   http::client client;
      16              :  *
      17              :  *   // Simple GET
      18              :  *   auto response = client.get("https://api.example.com/users");
      19              :  *   if (response) {
      20              :  *       std::cout << response.body() << std::endl;
      21              :  *   }
      22              :  *
      23              :  *   // POST with JSON
      24              :  *   auto response = client.post("https://api.example.com/users", R"({"name":"test"})");
      25              :  *
      26              :  *   // With configuration (fluent API)
      27              :  *   client.timeout(std::chrono::seconds(30)).verify_ssl(false);
      28              :  *   auto response = client.get("https://internal-api/data");
      29              :  *
      30              :  * For async/concurrent operations, use http::async_client instead.
      31              :  */
      32              : class client : public http_client_base {
      33              : private:
      34              :     boost::asio::io_context io_context_;
      35              : 
      36              :     // Internal helper to run an awaitable synchronously
      37              :     template<typename T>
      38          515 :     T exec(awaitable<T> coro) {
      39          515 :         T result;
      40         1030 :         co_spawn(io_context_, [&result, coro = std::move(coro)]() mutable -> awaitable<void> {
      41              :             result = co_await std::move(coro);
      42              :         }, detached);
      43          515 :         io_context_.run();
      44          515 :         io_context_.restart();
      45          515 :         return result;
      46            0 :     }
      47              : 
      48              : protected:
      49          537 :     boost::asio::io_context& get_io_context() override {
      50          537 :         return io_context_;
      51              :     }
      52              : 
      53              : public:
      54          568 :     client() = default;
      55          568 :     ~client() override = default;
      56              : 
      57              :     // ============================================
      58              :     // Synchronous HTTP methods
      59              :     // ============================================
      60              : 
      61          292 :     client_response get(const std::string& url, headers_map headers = {}) {
      62          292 :         return exec(http_client_base::get(url, std::move(headers)));
      63              :     }
      64              : 
      65           94 :     client_response post(const std::string& url, std::string body = {},
      66              :                          std::string content_type = "application/json", headers_map headers = {}) {
      67           94 :         return exec(http_client_base::post(url, std::move(body), std::move(content_type), std::move(headers)));
      68              :     }
      69              : 
      70              :     client_response post(const std::string& url, const form& form, headers_map headers = {}) {
      71              :         return exec(http_client_base::post(url, form, std::move(headers)));
      72              :     }
      73              : 
      74           19 :     client_response put(const std::string& url, std::string body = {},
      75              :                         std::string content_type = "application/json", headers_map headers = {}) {
      76           19 :         return exec(http_client_base::put(url, std::move(body), std::move(content_type), std::move(headers)));
      77              :     }
      78              : 
      79           15 :     client_response patch(const std::string& url, std::string body = {},
      80              :                           std::string content_type = "application/json", headers_map headers = {}) {
      81           15 :         return exec(http_client_base::patch(url, std::move(body), std::move(content_type), std::move(headers)));
      82              :     }
      83              : 
      84            7 :     client_response del(const std::string& url, headers_map headers = {}) {
      85            7 :         return exec(http_client_base::del(url, std::move(headers)));
      86              :     }
      87              : 
      88            7 :     client_response head(const std::string& url, headers_map headers = {}) {
      89            7 :         return exec(http_client_base::head(url, std::move(headers)));
      90              :     }
      91              : 
      92            7 :     client_response options(const std::string& url, headers_map headers = {}) {
      93            7 :         return exec(http_client_base::options(url, std::move(headers)));
      94              :     }
      95              : 
      96              :     // Generic send with custom request
      97           44 :     client_response send(std::shared_ptr<http_request> request) {
      98           44 :         return exec(http_client_base::send(std::move(request)));
      99              :     }
     100              : 
     101              :     // Streaming send
     102            2 :     stream_result send_streaming(std::shared_ptr<http_request> request, stream_callback callback) {
     103            2 :         return exec(http_client_base::send_streaming(std::move(request), std::move(callback)));
     104              :     }
     105              : 
     106              :     // ============================================
     107              :     // Request builder for fluent API
     108              :     // ============================================
     109              : 
     110              :     /**
     111              :      * Create a request builder for fluent API with streaming support.
     112              :      *
     113              :      * Usage:
     114              :      *   auto res = client.request("https://api.com/data")
     115              :      *       .header("Authorization", "Bearer xxx")
     116              :      *       .get();
     117              :      */
     118           55 :     request_builder<client> request(const std::string& url) {
     119           55 :         return request_builder<client>(this, url);
     120              :     }
     121              : 
     122              :     // ============================================
     123              :     // WebSocket
     124              :     // ============================================
     125              : 
     126              :     /**
     127              :      * Connect to a WebSocket server (simple API).
     128              :      *
     129              :      * Usage:
     130              :      *   if (auto ws = client.websocket("ws://server.com/path")) {
     131              :      *       ws->send_text("Hello!");
     132              :      *       auto [msg, binary] = ws->receive();
     133              :      *       ws->close();
     134              :      *   }
     135              :      */
     136           20 :     std::optional<websocket_client> websocket(const std::string& url,
     137              :                                                const std::string& subprotocol = "") {
     138           20 :         return exec(http_client_base::upgrade_websocket(url, subprotocol));
     139              :     }
     140              : 
     141              :     /**
     142              :      * Connect to a WebSocket server with custom request/headers (used by request_builder).
     143              :      */
     144            8 :     std::optional<websocket_client> websocket(std::shared_ptr<http_request> request,
     145              :                                                const std::string& subprotocol = "") {
     146            8 :         return exec(http_client_base::upgrade_websocket(std::move(request), subprotocol));
     147              :     }
     148              : };
     149              : 
     150              : } // namespace thinger::http
     151              : 
     152              : #endif
        

Generated by: LCOV version 2.0-1