From 9271436bbd15ae16b4cbf13944b0d08fb9383cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levent=20KARAG=C3=96L?= Date: Sat, 20 Apr 2024 16:23:51 +0300 Subject: [PATCH] Pointers replaced with smart pointers --- README.md | 42 +++++---- examples/main.cpp | 44 +++++++--- src/libcpp-http-client.hpp | 176 +++++++++++++++++++++---------------- test/test.cpp | 160 ++++++++++++++++++++++----------- 4 files changed, 267 insertions(+), 155 deletions(-) diff --git a/README.md b/README.md index 75c3327..a9d4694 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,10 @@ using namespace lklibs; int main() { + HttpClient httpClient; + // The simplest but slowest method if multiple calls will be made - auto response = HttpClient::getRequest("https://api.myproject.com?param1=7¶m2=test").get(); + auto response = httpClient.getRequest("https://api.myproject.com?param1=7¶m2=test").get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -95,11 +97,13 @@ using namespace lklibs; int main() { - auto response1 = HttpClient::getRequest("https://api.myproject.com/foo").get(); - auto response2 = HttpClient::getRequest("https://api.myproject.com/bar").get(); - auto response3 = HttpClient::getRequest("https://api.myproject.com/baz").get(); - auto response4 = HttpClient::getRequest("https://api.myproject.com/qux").get(); - auto response5 = HttpClient::getRequest("https://api.myproject.com/quux").get(); + HttpClient httpClient; + + auto response1 = httpClient.getRequest("https://api.myproject.com/foo").get(); + auto response2 = httpClient.getRequest("https://api.myproject.com/bar").get(); + auto response3 = httpClient.getRequest("https://api.myproject.com/baz").get(); + auto response4 = httpClient.getRequest("https://api.myproject.com/qux").get(); + auto response5 = httpClient.getRequest("https://api.myproject.com/quux").get(); // Takes 2.5 seconds in total @@ -119,11 +123,11 @@ using namespace lklibs; int main() { - auto future1 = HttpClient::getRequest("https://api.myproject.com/foo"); - auto future2 = HttpClient::getRequest("https://api.myproject.com/bar"); - auto future3 = HttpClient::getRequest("https://api.myproject.com/baz"); - auto future4 = HttpClient::getRequest("https://api.myproject.com/qux"); - auto future5 = HttpClient::getRequest("https://api.myproject.com/quux"); + auto future1 = httpClient.getRequest("https://api.myproject.com/foo"); + auto future2 = httpClient.getRequest("https://api.myproject.com/bar"); + auto future3 = httpClient.getRequest("https://api.myproject.com/baz"); + auto future4 = httpClient.getRequest("https://api.myproject.com/qux"); + auto future5 = httpClient.getRequest("https://api.myproject.com/quux"); auto response1 = future1.get(); auto response2 = future2.get(); @@ -159,7 +163,7 @@ using namespace lklibs; int main() { - auto response = HttpClient::getRequest("https://www.myinvalidurl.com").get(); + auto response = httpClient.getRequest("https://www.myinvalidurl.com").get(); // Instead of throwing an exception, the succeed field of the response object is set to false std::cout << "Succeed: " << response.succeed << std::endl; @@ -192,7 +196,7 @@ using namespace lklibs; int main() { // If you need to retrieve binary data such as an image, just pass the "returnAsBinary" parameter as true - auto response = HttpClient::getRequest("https://api.myproject.com/image/7", true).get(); + auto response = httpClient.getRequest("https://api.myproject.com/image/7", true).get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -224,7 +228,7 @@ int main() { headers["Custom-Header1"] = "value1"; headers["Custom-Header2"] = "value2"; - auto response = HttpClient::getRequest("https://api.myproject.com?param1=7¶m2=test", headers).get(); + auto response = httpClient.getRequest("https://api.myproject.com?param1=7¶m2=test", headers).get(); std::cout << "Succeed: " << response.succeed << std::endl; @@ -249,7 +253,7 @@ int main() { // You can send a POST request with form data in the payload std::string payload = "param1=7¶m2=test"; - auto response = HttpClient::postRequest("https://api.myproject.com", payload).get(); + auto response = httpClient.postRequest("https://api.myproject.com", payload).get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -280,7 +284,7 @@ int main() { headers["Content-Type"] = "application/json"; - auto response = HttpClient::postRequest("https://api.myproject.com", payload, headers).get(); + auto response = httpClient.postRequest("https://api.myproject.com", payload, headers).get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -305,9 +309,9 @@ int main() { std::string payload = "param1=7¶m2=test"; - auto future1 = HttpClient::putRequest("https://api.myproject.com", payload); - auto future2 = HttpClient::deleteRequest("https://api.myproject.com", payload); - auto future3 = HttpClient::patchRequest("https://api.myproject.com?param1=7¶m2=test"); + auto future1 = httpClient.putRequest("https://api.myproject.com", payload); + auto future2 = httpClient.deleteRequest("https://api.myproject.com", payload); + auto future3 = httpClient.patchRequest("https://api.myproject.com?param1=7¶m2=test"); auto response1 = future1.get(); auto response2 = future2.get(); diff --git a/examples/main.cpp b/examples/main.cpp index 5b4117b..fa524f4 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -5,8 +5,10 @@ using namespace lklibs; void simpleGet() { + HttpClient httpClient; + // The simplest but slowest method if multiple calls will be made - auto response = HttpClient::getRequest("https://httpbun.com/get?param1=7¶m2=test").get(); + auto response = httpClient.getRequest("https://httpbun.com/get?param1=7¶m2=test").get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -15,10 +17,12 @@ void simpleGet() { void nonBlockingGet() { + HttpClient httpClient; + // All requests are made one after the other without waiting for a response - auto future1 = HttpClient::getRequest("https://httpbun.com/get?param1=1¶m2=test1"); - auto future2 = HttpClient::getRequest("https://httpbun.com/get?param1=2¶m2=test2"); - auto future3 = HttpClient::getRequest("https://httpbun.com/get?param1=3¶m2=test3"); + auto future1 = httpClient.getRequest("https://httpbun.com/get?param1=1¶m2=test1"); + auto future2 = httpClient.getRequest("https://httpbun.com/get?param1=2¶m2=test2"); + auto future3 = httpClient.getRequest("https://httpbun.com/get?param1=3¶m2=test3"); // Then all the answers are received. Thus, 3 requests are sent in parallel auto response1 = future1.get(); @@ -40,8 +44,10 @@ void nonBlockingGet() { void receiveBinaryData() { + HttpClient httpClient; + // If you need to retrieve binary data such as an image, just pass the "returnAsBinary" parameter as true - auto response = HttpClient::getRequest("https://httpbun.com/bytes/100", true).get(); + auto response = httpClient.getRequest("https://httpbun.com/bytes/100", true).get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -52,8 +58,10 @@ void receiveBinaryData() { void receiveError() { + HttpClient httpClient; + // This is an exception free library. If an error occurs, no exception is thrown - auto response = HttpClient::getRequest("https://httpbun.com/not_found").get(); + auto response = httpClient.getRequest("https://httpbun.com/not_found").get(); // Instead, the succeed field of the response object is set to false std::cout << "Succeed: " << response.succeed << std::endl; @@ -67,23 +75,27 @@ void receiveError() { void sendingHttpHeaders() { + HttpClient httpClient; + // You can send custom headers in a string/string map auto headers = std::map(); headers["Custom-Header1"] = "value1"; headers["Custom-Header2"] = "value2"; - auto response = HttpClient::getRequest("https://httpbun.com/get?param1=7¶m2=test", headers).get(); + auto response = httpClient.getRequest("https://httpbun.com/get?param1=7¶m2=test", headers).get(); std::cout << "Succeed: " << response.succeed << std::endl; } void simplePostWithFormData() { + HttpClient httpClient; + // You can send a POST request with form data in the payload std::string payload = "param1=7¶m2=test"; - auto response = HttpClient::postRequest("https://httpbun.com/post", payload).get(); + auto response = httpClient.postRequest("https://httpbun.com/post", payload).get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -92,6 +104,8 @@ void simplePostWithFormData() { void simplePostWithJSONData() { + HttpClient httpClient; + std::string payload = R"({"param1": 7, "param2": "test"})"; // You need to send the "Content-Type" as "application/json" in the HTTP Header, if you need to send json data in the payload @@ -99,7 +113,7 @@ void simplePostWithJSONData() { headers["Content-Type"] = "application/json"; - auto response = HttpClient::postRequest("https://httpbun.com/post", payload, headers).get(); + auto response = httpClient.postRequest("https://httpbun.com/post", payload, headers).get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -108,10 +122,12 @@ void simplePostWithJSONData() { void simplePutWithFormData() { + HttpClient httpClient; + // You can send a PUT request with form data in the payload just like POST std::string payload = "param1=7¶m2=test"; - auto response = HttpClient::putRequest("https://httpbun.com/put", payload).get(); + auto response = httpClient.putRequest("https://httpbun.com/put", payload).get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -120,10 +136,12 @@ void simplePutWithFormData() { void simpleDeleteWithFormData() { + HttpClient httpClient; + // You can send a DELETE request with form data in the payload just like POST std::string payload = "param1=7¶m2=test"; - auto response = HttpClient::deleteRequest("https://httpbun.com/delete", payload).get(); + auto response = httpClient.deleteRequest("https://httpbun.com/delete", payload).get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; @@ -132,8 +150,10 @@ void simpleDeleteWithFormData() { void simplePatch() { + HttpClient httpClient; + // You can send a PATCH request with QueryString just like GET - auto response = HttpClient::patchRequest("https://httpbun.com/patch?param1=7¶m2=test").get(); + auto response = httpClient.patchRequest("https://httpbun.com/patch?param1=7¶m2=test").get(); std::cout << "Succeed: " << response.succeed << std::endl; std::cout << "Http Status Code: " << response.statusCode << std::endl; diff --git a/src/libcpp-http-client.hpp b/src/libcpp-http-client.hpp index 5bef1d4..a4b9e90 100644 --- a/src/libcpp-http-client.hpp +++ b/src/libcpp-http-client.hpp @@ -36,6 +36,7 @@ SOFTWARE. #include #include #include +#include #include namespace lklibs { @@ -82,13 +83,21 @@ namespace lklibs { class HttpClient { public: + HttpClient() { + curl_global_init(CURL_GLOBAL_DEFAULT); + } + + ~HttpClient() { + curl_global_cleanup(); + } + /** * @brief Makes an HTTP GET request for the given URL and returns the result * * @param url: Request URL * @return Result of the request (see HttpResult object for details) */ - static std::future getRequest(const std::string &url) noexcept { + std::future getRequest(const std::string &url) noexcept { return request(url, "GET", "", false, {}); } @@ -100,7 +109,7 @@ namespace lklibs { * @param returnAsBinary: Return result as binary instead of string (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future getRequest(const std::string &url, bool returnAsBinary) noexcept { + std::future getRequest(const std::string &url, bool returnAsBinary) noexcept { return request(url, "GET", "", returnAsBinary, {}); } @@ -112,7 +121,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future getRequest(const std::string &url, const std::map &headers) noexcept { + std::future getRequest(const std::string &url, const std::map &headers) noexcept { return request(url, "GET", "", false, headers); } @@ -125,7 +134,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future getRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { + std::future getRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { return request(url, "GET", "", returnAsBinary, headers); } @@ -137,7 +146,7 @@ namespace lklibs { * @param url: Request URL * @return Result of the request (see HttpResult object for details) */ - static std::future postRequest(const std::string &url) noexcept { + std::future postRequest(const std::string &url) noexcept { return request(url, "POST", "", false, {}); } @@ -149,7 +158,7 @@ namespace lklibs { * @param payload: Payload to be sent with the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future postRequest(const std::string &url, const std::string &payload) noexcept { + std::future postRequest(const std::string &url, const std::string &payload) noexcept { return request(url, "POST", payload, false, {}); } @@ -161,7 +170,7 @@ namespace lklibs { * @param returnAsBinary: Return result as binary instead of string (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future postRequest(const std::string &url, bool returnAsBinary) noexcept { + std::future postRequest(const std::string &url, bool returnAsBinary) noexcept { return request(url, "POST", "", returnAsBinary, {}); } @@ -173,7 +182,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future postRequest(const std::string &url, const std::map &headers) noexcept { + std::future postRequest(const std::string &url, const std::map &headers) noexcept { return request(url, "POST", "", false, headers); } @@ -186,7 +195,7 @@ namespace lklibs { * @param returnAsBinary: Return result as binary instead of string (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future postRequest(const std::string &url, const std::string &payload, bool returnAsBinary) noexcept { + std::future postRequest(const std::string &url, const std::string &payload, bool returnAsBinary) noexcept { return request(url, "POST", payload, returnAsBinary, {}); } @@ -199,7 +208,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future postRequest(const std::string &url, const std::string &payload, const std::map &headers) noexcept { + std::future postRequest(const std::string &url, const std::string &payload, const std::map &headers) noexcept { return request(url, "POST", payload, false, headers); } @@ -212,7 +221,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future postRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { + std::future postRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { return request(url, "POST", "", returnAsBinary, headers); } @@ -226,7 +235,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future postRequest(const std::string &url, const std::string &payload, bool returnAsBinary, const std::map &headers) noexcept { + std::future postRequest(const std::string &url, const std::string &payload, bool returnAsBinary, const std::map &headers) noexcept { return request(url, "POST", payload, returnAsBinary, headers); } @@ -238,7 +247,7 @@ namespace lklibs { * @param url: Request URL * @return Result of the request (see HttpResult object for details) */ - static std::future putRequest(const std::string &url) noexcept { + std::future putRequest(const std::string &url) noexcept { return request(url, "PUT", "", false, {}); } @@ -250,7 +259,7 @@ namespace lklibs { * @param payload: Payload to be sent with the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future putRequest(const std::string &url, const std::string &payload) noexcept { + std::future putRequest(const std::string &url, const std::string &payload) noexcept { return request(url, "PUT", payload, false, {}); } @@ -262,7 +271,7 @@ namespace lklibs { * @param returnAsBinary: Return result as binary instead of string (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future putRequest(const std::string &url, bool returnAsBinary) noexcept { + std::future putRequest(const std::string &url, bool returnAsBinary) noexcept { return request(url, "PUT", "", returnAsBinary, {}); } @@ -274,7 +283,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future putRequest(const std::string &url, const std::map &headers) noexcept { + std::future putRequest(const std::string &url, const std::map &headers) noexcept { return request(url, "PUT", "", false, headers); } @@ -287,7 +296,7 @@ namespace lklibs { * @param returnAsBinary: Return result as binary instead of string (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future putRequest(const std::string &url, const std::string &payload, bool returnAsBinary) noexcept { + std::future putRequest(const std::string &url, const std::string &payload, bool returnAsBinary) noexcept { return request(url, "PUT", payload, returnAsBinary, {}); } @@ -300,7 +309,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future putRequest(const std::string &url, const std::string &payload, const std::map &headers) noexcept { + std::future putRequest(const std::string &url, const std::string &payload, const std::map &headers) noexcept { return request(url, "PUT", payload, false, headers); } @@ -313,7 +322,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future putRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { + std::future putRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { return request(url, "PUT", "", returnAsBinary, headers); } @@ -327,7 +336,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future putRequest(const std::string &url, const std::string &payload, bool returnAsBinary, const std::map &headers) noexcept { + std::future putRequest(const std::string &url, const std::string &payload, bool returnAsBinary, const std::map &headers) noexcept { return request(url, "PUT", payload, returnAsBinary, headers); } @@ -339,7 +348,7 @@ namespace lklibs { * @param url: Request URL * @return Result of the request (see HttpResult object for details) */ - static std::future deleteRequest(const std::string &url) noexcept { + std::future deleteRequest(const std::string &url) noexcept { return request(url, "DELETE", "", false, {}); } @@ -351,7 +360,7 @@ namespace lklibs { * @param payload: Payload to be sent with the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future deleteRequest(const std::string &url, const std::string &payload) noexcept { + std::future deleteRequest(const std::string &url, const std::string &payload) noexcept { return request(url, "DELETE", payload, false, {}); } @@ -363,7 +372,7 @@ namespace lklibs { * @param returnAsBinary: Return result as binary instead of string (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future deleteRequest(const std::string &url, bool returnAsBinary) noexcept { + std::future deleteRequest(const std::string &url, bool returnAsBinary) noexcept { return request(url, "DELETE", "", returnAsBinary, {}); } @@ -375,7 +384,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future deleteRequest(const std::string &url, const std::map &headers) noexcept { + std::future deleteRequest(const std::string &url, const std::map &headers) noexcept { return request(url, "DELETE", "", false, headers); } @@ -388,7 +397,7 @@ namespace lklibs { * @param returnAsBinary: Return result as binary instead of string (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future deleteRequest(const std::string &url, const std::string &payload, bool returnAsBinary) noexcept { + std::future deleteRequest(const std::string &url, const std::string &payload, bool returnAsBinary) noexcept { return request(url, "DELETE", payload, returnAsBinary, {}); } @@ -401,7 +410,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future deleteRequest(const std::string &url, const std::string &payload, const std::map &headers) noexcept { + std::future deleteRequest(const std::string &url, const std::string &payload, const std::map &headers) noexcept { return request(url, "DELETE", payload, false, headers); } @@ -414,7 +423,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future deleteRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { + std::future deleteRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { return request(url, "DELETE", "", returnAsBinary, headers); } @@ -428,7 +437,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future deleteRequest(const std::string &url, const std::string &payload, bool returnAsBinary, const std::map &headers) noexcept { + std::future deleteRequest(const std::string &url, const std::string &payload, bool returnAsBinary, const std::map &headers) noexcept { return request(url, "DELETE", payload, returnAsBinary, headers); } @@ -440,7 +449,7 @@ namespace lklibs { * @param url: Request URL * @return Result of the request (see HttpResult object for details) */ - static std::future patchRequest(const std::string &url) noexcept { + std::future patchRequest(const std::string &url) noexcept { return request(url, "PATCH", "", false, {}); } @@ -452,7 +461,7 @@ namespace lklibs { * @param returnAsBinary: Return result as binary instead of string (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future patchRequest(const std::string &url, bool returnAsBinary) noexcept { + std::future patchRequest(const std::string &url, bool returnAsBinary) noexcept { return request(url, "PATCH", "", returnAsBinary, {}); } @@ -464,7 +473,7 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future patchRequest(const std::string &url, const std::map &headers) noexcept { + std::future patchRequest(const std::string &url, const std::map &headers) noexcept { return request(url, "PATCH", "", false, headers); } @@ -477,89 +486,108 @@ namespace lklibs { * @param headers: HTTP Header information to be sent when making the request (Optional) * @return Result of the request (see HttpResult object for details) */ - static std::future patchRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { + std::future patchRequest(const std::string &url, bool returnAsBinary, const std::map &headers) noexcept { return request(url, "PATCH", "", returnAsBinary, headers); } private: - static std::future request(const std::string &url, const std::string &method, const std::string &payload, bool returnAsBinary, const std::map &headers) noexcept { + struct CurlDeleter { - return std::async(std::launch::async, [=]() -> HttpResult { + void operator()(CURL* ptr) { - CURL* curl; - CURLcode res; - struct curl_slist* headerList = nullptr; - std::string stringBuffer; - std::vector binaryBuffer; - int statusCode = 0; + if (ptr) { - curl_global_init(CURL_GLOBAL_DEFAULT); - curl = curl_easy_init(); + curl_easy_cleanup(ptr); + } + } + }; - if (curl) { + struct CurlSlistDeleter { - for (const auto &header: headers) { + void operator()(curl_slist* ptr) { - std::string headerStr = header.first + ": " + header.second; + if (ptr) { - headerList = curl_slist_append(headerList, headerStr.c_str()); - } + curl_slist_free_all(ptr); + } + } + }; - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList); - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); + std::future request(const std::string &url, const std::string &method, const std::string &payload, bool returnAsBinary, const std::map &headers) { - if ((method == "POST" || method == "PUT" || method == "DELETE") && !payload.empty()) { + return std::async(std::launch::async, [url, method, payload, returnAsBinary, headers]() -> HttpResult { - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str()); - } + std::unique_ptr curl(curl_easy_init()); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str()); + if (!curl) { - if (returnAsBinary) { + return {false, "", {}, 0, "CURL initialization failed"}; + } - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, binaryWriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &binaryBuffer); + std::unique_ptr headerList(nullptr); - } else { + for (const auto &header: headers) { - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, textWriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stringBuffer); - } + std::string headerStr = header.first + ": " + header.second; - res = curl_easy_perform(curl); + headerList.reset(curl_slist_append(headerList.release(), headerStr.c_str())); + } - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode); + std::string stringBuffer; + std::vector binaryBuffer; + int statusCode = 0; - curl_easy_cleanup(curl); - curl_slist_free_all(headerList); + curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headerList.get()); + curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl.get(), CURLOPT_CUSTOMREQUEST, method.c_str()); - if (res == CURLE_OK && statusCode == 200) { + if (!payload.empty()) { - return {true, stringBuffer, binaryBuffer, statusCode, ""}; + curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, payload.c_str()); + } - } else { + if (returnAsBinary) { - return {false, stringBuffer, binaryBuffer, statusCode, curl_easy_strerror(res)}; - } + curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, binaryWriteCallback); + curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &binaryBuffer); + + } else { + + curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, textWriteCallback); + curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &stringBuffer); } - curl_global_cleanup(); + CURLcode res = curl_easy_perform(curl.get()); + curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &statusCode); + + if (res == CURLE_OK && statusCode >= 200 && statusCode < 300) { - return {false, "", {}, 0, "CURL initialization failed"}; + return {true, stringBuffer, binaryBuffer, statusCode, ""}; + + } else { + + std::string errorMessage = curl_easy_strerror(res); + + if (res == CURLE_OK) { + + errorMessage = "HTTP Error: " + std::to_string(statusCode); + } + + return {false, stringBuffer, binaryBuffer, statusCode, errorMessage}; + } }); } - static size_t textWriteCallback(void* contents, size_t size, size_t nmemb, void* userp) noexcept { + static size_t textWriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { ((std::string*) userp)->append((char*) contents, size * nmemb); return size * nmemb; } - static size_t binaryWriteCallback(void* contents, size_t size, size_t nmemb, void* userp) noexcept { + static size_t binaryWriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { auto &buffer = *static_cast*>(userp); diff --git a/test/test.cpp b/test/test.cpp index 86889d3..b948912 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -7,7 +7,9 @@ using json = nlohmann::json; TEST(HttpGetTest, HttpGetRequestMustBeCompletedSuccessfullyInItsSimplestForm) { - auto response = HttpClient::getRequest("https://httpbun.com/get?param1=7¶m2=test").get(); + HttpClient httpClient; + + auto response = httpClient.getRequest("https://httpbun.com/get?param1=7¶m2=test").get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -24,9 +26,11 @@ TEST(HttpGetTest, HttpGetRequestMustBeCompletedSuccessfullyInItsSimplestForm) { TEST(HttpGetTest, MultipleHttpGetRequestMustBeCompletedSuccessfullyInNonBlockingForm) { - auto future1 = HttpClient::getRequest("https://httpbun.com/get?param1=1¶m2=test1"); - auto future2 = HttpClient::getRequest("https://httpbun.com/get?param1=2¶m2=test2"); - auto future3 = HttpClient::getRequest("https://httpbun.com/get?param1=3¶m2=test3"); + HttpClient httpClient; + + auto future1 = httpClient.getRequest("https://httpbun.com/get?param1=1¶m2=test1"); + auto future2 = httpClient.getRequest("https://httpbun.com/get?param1=2¶m2=test2"); + auto future3 = httpClient.getRequest("https://httpbun.com/get?param1=3¶m2=test3"); auto response1 = future1.get(); auto response2 = future2.get(); @@ -69,7 +73,9 @@ TEST(HttpGetTest, MultipleHttpGetRequestMustBeCompletedSuccessfullyInNonBlocking TEST(HttpGetTest, ResponseOfAnHttpGetRequestCanBeReceivedInBinaryFormat) { - auto response = HttpClient::getRequest("https://httpbun.com/bytes/100", true).get(); + HttpClient httpClient; + + auto response = httpClient.getRequest("https://httpbun.com/bytes/100", true).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -80,19 +86,23 @@ TEST(HttpGetTest, ResponseOfAnHttpGetRequestCanBeReceivedInBinaryFormat) { TEST(HttpGetTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpGetRequestMadeToAnInvalidAddress) { - auto response = HttpClient::getRequest("https://httpbun.com/not_found").get(); + HttpClient httpClient; + + auto response = httpClient.getRequest("https://httpbun.com/not_found").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404";; + ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } TEST(HttpGetTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpGetRequestForAnotherError) { - auto response = HttpClient::getRequest("https://httpbun.com/bearer").get(); + HttpClient httpClient; + + auto response = httpClient.getRequest("https://httpbun.com/bearer").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401";; + ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } @@ -103,7 +113,9 @@ TEST(HttpGetTest, HttpHeadersCanBeSentWithTheHttpGetRequest) { headers["Custom-Header1"] = "value1"; headers["Custom-Header2"] = "value2"; - auto response = HttpClient::getRequest("https://httpbun.com/get?param1=7¶m2=test", headers).get(); + HttpClient httpClient; + + auto response = httpClient.getRequest("https://httpbun.com/get?param1=7¶m2=test", headers).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -125,7 +137,9 @@ TEST(HttpPostTest, HttpPostRequestMustBeCompletedSuccessfullyInItsSimplestForm) std::string payload = "param1=7¶m2=test"; - auto response = HttpClient::postRequest("https://httpbun.com/post", payload).get(); + HttpClient httpClient; + + auto response = httpClient.postRequest("https://httpbun.com/post", payload).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -146,9 +160,11 @@ TEST(HttpPostTest, MultipleHttpPostRequestMustBeCompletedSuccessfullyInNonBlocki std::string payload2 = "param1=2¶m2=test2"; std::string payload3 = "param1=3¶m2=test3"; - auto future1 = HttpClient::postRequest("https://httpbun.com/post", payload1); - auto future2 = HttpClient::postRequest("https://httpbun.com/post", payload2); - auto future3 = HttpClient::postRequest("https://httpbun.com/post", payload3); + HttpClient httpClient; + + auto future1 = httpClient.postRequest("https://httpbun.com/post", payload1); + auto future2 = httpClient.postRequest("https://httpbun.com/post", payload2); + auto future3 = httpClient.postRequest("https://httpbun.com/post", payload3); auto response1 = future1.get(); auto response2 = future2.get(); @@ -191,7 +207,9 @@ TEST(HttpPostTest, MultipleHttpPostRequestMustBeCompletedSuccessfullyInNonBlocki TEST(HttpPostTest, ResponseOfAnHttpPostRequestCanBeReceivedInBinaryFormat) { - auto response = HttpClient::postRequest("https://httpbun.com/bytes/100", true).get(); + HttpClient httpClient; + + auto response = httpClient.postRequest("https://httpbun.com/bytes/100", true).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -202,19 +220,23 @@ TEST(HttpPostTest, ResponseOfAnHttpPostRequestCanBeReceivedInBinaryFormat) { TEST(HttpPostTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPostRequestMadeToAnInvalidAddress) { - auto response = HttpClient::postRequest("https://httpbun.com/not_found").get(); + HttpClient httpClient; + + auto response = httpClient.postRequest("https://httpbun.com/not_found").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404";; + ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } TEST(HttpPostTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPostRequestForAnotherError) { - auto response = HttpClient::postRequest("https://httpbun.com/bearer").get(); + HttpClient httpClient; + + auto response = httpClient.postRequest("https://httpbun.com/bearer").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401";; + ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } @@ -228,7 +250,9 @@ TEST(HttpPostTest, HttpHeadersCanBeSentWithTheHttpPostRequest) { headers["Custom-Header1"] = "value1"; headers["Custom-Header2"] = "value2"; - auto response = HttpClient::postRequest("https://httpbun.com/post", payload, headers).get(); + HttpClient httpClient; + + auto response = httpClient.postRequest("https://httpbun.com/post", payload, headers).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -251,7 +275,9 @@ TEST(HttpPutTest, HttpPutRequestMustBeCompletedSuccessfullyInItsSimplestForm) { std::string payload = "param1=7¶m2=test"; - auto response = HttpClient::putRequest("https://httpbun.com/put", payload).get(); + HttpClient httpClient; + + auto response = httpClient.putRequest("https://httpbun.com/put", payload).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -272,9 +298,11 @@ TEST(HttpPutTest, MultipleHttpPutRequestMustBeCompletedSuccessfullyInNonBlocking std::string payload2 = "param1=2¶m2=test2"; std::string payload3 = "param1=3¶m2=test3"; - auto future1 = HttpClient::putRequest("https://httpbun.com/put", payload1); - auto future2 = HttpClient::putRequest("https://httpbun.com/put", payload2); - auto future3 = HttpClient::putRequest("https://httpbun.com/put", payload3); + HttpClient httpClient; + + auto future1 = httpClient.putRequest("https://httpbun.com/put", payload1); + auto future2 = httpClient.putRequest("https://httpbun.com/put", payload2); + auto future3 = httpClient.putRequest("https://httpbun.com/put", payload3); auto response1 = future1.get(); auto response2 = future2.get(); @@ -317,7 +345,9 @@ TEST(HttpPutTest, MultipleHttpPutRequestMustBeCompletedSuccessfullyInNonBlocking TEST(HttpPutTest, ResponseOfAnHttpPutRequestCanBeReceivedInBinaryFormat) { - auto response = HttpClient::putRequest("https://httpbun.com/bytes/100", true).get(); + HttpClient httpClient; + + auto response = httpClient.putRequest("https://httpbun.com/bytes/100", true).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -328,19 +358,23 @@ TEST(HttpPutTest, ResponseOfAnHttpPutRequestCanBeReceivedInBinaryFormat) { TEST(HttpPutTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPutRequestMadeToAnInvalidAddress) { - auto response = HttpClient::putRequest("https://httpbun.com/not_found").get(); + HttpClient httpClient; + + auto response = httpClient.putRequest("https://httpbun.com/not_found").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404";; + ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } TEST(HttpPutTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPutRequestForAnotherError) { - auto response = HttpClient::putRequest("https://httpbun.com/bearer").get(); + HttpClient httpClient; + + auto response = httpClient.putRequest("https://httpbun.com/bearer").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401";; + ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } @@ -354,7 +388,9 @@ TEST(HttpPutTest, HttpHeadersCanBeSentWithTheHttpPutRequest) { headers["Custom-Header1"] = "value1"; headers["Custom-Header2"] = "value2"; - auto response = HttpClient::putRequest("https://httpbun.com/put", payload, headers).get(); + HttpClient httpClient; + + auto response = httpClient.putRequest("https://httpbun.com/put", payload, headers).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -377,7 +413,9 @@ TEST(HttpDeleteTest, HttpDeleteRequestMustBeCompletedSuccessfullyInItsSimplestFo std::string payload = "param1=7¶m2=test"; - auto response = HttpClient::deleteRequest("https://httpbun.com/delete", payload).get(); + HttpClient httpClient; + + auto response = httpClient.deleteRequest("https://httpbun.com/delete", payload).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -398,9 +436,11 @@ TEST(HttpDeleteTest, MultipleHttpDeleteRequestMustBeCompletedSuccessfullyInNonBl std::string payload2 = "param1=2¶m2=test2"; std::string payload3 = "param1=3¶m2=test3"; - auto future1 = HttpClient::deleteRequest("https://httpbun.com/delete", payload1); - auto future2 = HttpClient::deleteRequest("https://httpbun.com/delete", payload2); - auto future3 = HttpClient::deleteRequest("https://httpbun.com/delete", payload3); + HttpClient httpClient; + + auto future1 = httpClient.deleteRequest("https://httpbun.com/delete", payload1); + auto future2 = httpClient.deleteRequest("https://httpbun.com/delete", payload2); + auto future3 = httpClient.deleteRequest("https://httpbun.com/delete", payload3); auto response1 = future1.get(); auto response2 = future2.get(); @@ -443,7 +483,9 @@ TEST(HttpDeleteTest, MultipleHttpDeleteRequestMustBeCompletedSuccessfullyInNonBl TEST(HttpDeleteTest, ResponseOfAnHttpDeleteRequestCanBeReceivedInBinaryFormat) { - auto response = HttpClient::deleteRequest("https://httpbun.com/bytes/100", true).get(); + HttpClient httpClient; + + auto response = httpClient.deleteRequest("https://httpbun.com/bytes/100", true).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -454,19 +496,23 @@ TEST(HttpDeleteTest, ResponseOfAnHttpDeleteRequestCanBeReceivedInBinaryFormat) { TEST(HttpDeleteTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpDeleteRequestMadeToAnInvalidAddress) { - auto response = HttpClient::deleteRequest("https://httpbun.com/not_found").get(); + HttpClient httpClient; + + auto response = httpClient.deleteRequest("https://httpbun.com/not_found").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404";; + ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } TEST(HttpDeleteTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpDeleteRequestForAnotherError) { - auto response = HttpClient::deleteRequest("https://httpbun.com/bearer").get(); + HttpClient httpClient; + + auto response = httpClient.deleteRequest("https://httpbun.com/bearer").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401";; + ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } @@ -480,7 +526,9 @@ TEST(HttpDeleteTest, HttpHeadersCanBeSentWithTheHttpDeleteRequest) { headers["Custom-Header1"] = "value1"; headers["Custom-Header2"] = "value2"; - auto response = HttpClient::deleteRequest("https://httpbun.com/delete", payload, headers).get(); + HttpClient httpClient; + + auto response = httpClient.deleteRequest("https://httpbun.com/delete", payload, headers).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -501,7 +549,9 @@ TEST(HttpDeleteTest, HttpHeadersCanBeSentWithTheHttpDeleteRequest) { TEST(HttpPatchTest, HttpPatchRequestMustBeCompletedSuccessfullyInItsSimplestForm) { - auto response = HttpClient::patchRequest("https://httpbun.com/patch?param1=7¶m2=test").get(); + HttpClient httpClient; + + auto response = httpClient.patchRequest("https://httpbun.com/patch?param1=7¶m2=test").get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -518,9 +568,11 @@ TEST(HttpPatchTest, HttpPatchRequestMustBeCompletedSuccessfullyInItsSimplestForm TEST(HttpPatchTest, MultipleHttpPatchRequestMustBeCompletedSuccessfullyInNonBlockingForm) { - auto future1 = HttpClient::patchRequest("https://httpbun.com/patch?param1=1¶m2=test1"); - auto future2 = HttpClient::patchRequest("https://httpbun.com/patch?param1=2¶m2=test2"); - auto future3 = HttpClient::patchRequest("https://httpbun.com/patch?param1=3¶m2=test3"); + HttpClient httpClient; + + auto future1 = httpClient.patchRequest("https://httpbun.com/patch?param1=1¶m2=test1"); + auto future2 = httpClient.patchRequest("https://httpbun.com/patch?param1=2¶m2=test2"); + auto future3 = httpClient.patchRequest("https://httpbun.com/patch?param1=3¶m2=test3"); auto response1 = future1.get(); auto response2 = future2.get(); @@ -563,7 +615,9 @@ TEST(HttpPatchTest, MultipleHttpPatchRequestMustBeCompletedSuccessfullyInNonBloc TEST(HttpPatchTest, ResponseOfAnHttpPatchRequestCanBeReceivedInBinaryFormat) { - auto response = HttpClient::patchRequest("https://httpbun.com/bytes/100", true).get(); + HttpClient httpClient; + + auto response = httpClient.patchRequest("https://httpbun.com/bytes/100", true).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200"; @@ -574,19 +628,23 @@ TEST(HttpPatchTest, ResponseOfAnHttpPatchRequestCanBeReceivedInBinaryFormat) { TEST(HttpPatchTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPatchRequestMadeToAnInvalidAddress) { - auto response = HttpClient::patchRequest("https://httpbun.com/not_found").get(); + HttpClient httpClient; + + auto response = httpClient.patchRequest("https://httpbun.com/not_found").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404";; + ASSERT_EQ(response.statusCode, 404) << "HTTP Status Code is not 404"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } TEST(HttpPatchTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPatchRequestForAnotherError) { - auto response = HttpClient::patchRequest("https://httpbun.com/bearer").get(); + HttpClient httpClient; + + auto response = httpClient.patchRequest("https://httpbun.com/bearer").get(); ASSERT_FALSE(response.succeed) << "HTTP Request failed"; - ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401";; + ASSERT_EQ(response.statusCode, 401) << "HTTP Status Code is not 401"; ASSERT_FALSE(response.errorMessage.empty()) << "HTTP Error Message is empty"; } @@ -598,7 +656,9 @@ TEST(HttpPatchTest, HttpHeadersCanBeSentWithTheHttpPatchRequest) { headers["Custom-Header1"] = "value1"; headers["Custom-Header2"] = "value2"; - auto response = HttpClient::patchRequest("https://httpbun.com/patch?param1=7¶m2=test", headers).get(); + HttpClient httpClient; + + auto response = httpClient.patchRequest("https://httpbun.com/patch?param1=7¶m2=test", headers).get(); ASSERT_TRUE(response.succeed) << "HTTP Request failed"; ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200";