{"id":14990033,"url":"https://github.com/jgaa/restincurl","last_synced_at":"2025-04-12T02:03:49.429Z","repository":{"id":65097086,"uuid":"146943568","full_name":"jgaa/RESTinCurl","owner":"jgaa","description":"Modern C++ header only library wrapper around libcurl","archived":false,"fork":false,"pushed_at":"2023-06-22T15:12:32.000Z","size":126,"stargazers_count":30,"open_issues_count":1,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-12T02:03:43.432Z","etag":null,"topics":["cpp14","libcurl","rest-client"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jgaa.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-31T21:24:49.000Z","updated_at":"2024-10-29T15:05:59.000Z","dependencies_parsed_at":"2024-09-15T17:22:20.875Z","dependency_job_id":null,"html_url":"https://github.com/jgaa/RESTinCurl","commit_stats":{"total_commits":85,"total_committers":3,"mean_commits":"28.333333333333332","dds":"0.15294117647058825","last_synced_commit":"8c597361b941ab771d0327167c2cece2901715a9"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2FRESTinCurl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2FRESTinCurl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2FRESTinCurl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgaa%2FRESTinCurl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jgaa","download_url":"https://codeload.github.com/jgaa/RESTinCurl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248505863,"owners_count":21115354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp14","libcurl","rest-client"],"created_at":"2024-09-24T14:19:21.804Z","updated_at":"2025-04-12T02:03:49.398Z","avatar_url":"https://github.com/jgaa.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# REST in Curl - Modern C++ header only library wrapper around libcurl\n\nC++ is fun. Boost::asio is lots of fun. Unfortunately, in some projects, they cannot be used without introducing great pain. That's why we need \nthe [*RESTinCurl*](https://github.com/jgaa/RESTinCurl) library.\nFor desktop and server projects, I personally prefer the much more interesting [restc-cpp](https://github.com/jgaa/restc-cpp) project.\n\n*RESTinCurl* is a very simple library that use the C library libcurl to perform HTTP client operations on web servers. It's targeting REST api's using HTTP and (probably) json. Restincurl does not provide json by itself. In my own projects, I use the excellent [nlohmann/json](https://github.com/nlohmann/json) header only library.\n\n## Design Goals\n\n- We use libcurl to keep the code size and dependencies at a minimum (for mobile and IOT). No boost library dependencies.\n- IO must be asynchronous, allowing any realistic numbers of REST requests from a single worker thread.\n- We must be able to shut down immediately, killing the worker thread at any time and cleaning up.\n- The library must use resources in a sane way, and silently shut down the worker thread and curl connection pool when it has been idle for a while.\n- Utilize C++14 to keep simple things simple.\n\n## Features\n\n- Very simple to use. You don't need to understand the inner workings of libcurl to use RESTinCurl!\n- Limited use of C++ templates to keep the binary size down. The library is geared towards mobile/IOT use-cases.\n- Supports all standard HTTP request types.\n- Supports synchronous and asynchronous requests (using the same API).\n- Exposes a request-builder class to make it dead simple to express requests.\n- Flexible logging.\n- Hides libcurl's awkward data callbacks and let's you work with std::string's in stead (if you want to).\n- Exposes all libcurl's options to you, via convenience methods, or directly.\n- Implements it's own asynchronous event-loop, and expose only a simple, modern, intuitive API to your code.\n- One instance use only one worker-thread. The thread is started on demand and stopped when the instance has been idle for a while.\n- Tuned towards REST/Json use-cases (but still usable for general/binary HTTP requests).\n- Supports sending files as raw data or MIME attachments.\n\n## How to use it in your C++ project\n\nYou can add it to you project as a git sub-module, download it as part of your\nprojects build (from CMake or whatever magic you use), or you can just\ndownload the header and copy it to your project (if you copy it, you should\npay attention to new releases in case there are any security fixes).\n\nThe project have a `CMakeLists.txt`. This used to build and run the tests\nwith cmake . It's not required in order to use the library. All yo need to do\nis to include the header-file.\n\n## External dependencies\n\n- the C++14 standard library\n- libcurl\n\n## How it works\n\nUsing *RESTinCurl* is simple.\n\nYou build a query, and provide a functor that gets called when the request finish (or fail).\n\nExample:\n\n```C++\nrestincurl::Client client;\nclient.Build()-\u003eGet(\"https://api.example.com/\")\n    .WithCompletion([](const restincurl::Result\u0026 result) {\n       std::clog \u003c\u003c \"It works!\" \u003c\u003c std::endl;\n    })\n    .Execute();\n\n```\n\n## Data\n\n*RESTinCurl* is a very thin wrapper over libcurl. Libcurl reads and writes payload data from / to\nC callback functions while serving a request. That gives a lot of flexibility, but it's a bit awkward\nto implement. RESTinCurl gives you full flexibility in that you can use the C API for this, by providing\nyour own callback functions, you can use a C++ template abstraction that reads/writes to a container, \nor you can simply use std::string buffers. For json payloads, strings are perfect, and RESTinCurl \nprovides a very simple and intuitive interface. \n\n## Threading model\n\nIn asynchronous mode (the default mode of operation), each instance of a Client class will\nstart one worker-thread that will deal with all concurrent requests performed by that\ninstance. The worker-thread is started when the first request is made, and it will be\nterminated after a configurable timeout-period when the client is idle. \n\nAsynchronous requests returns immediately, and an (optional) callback will be called when the \nrequest finish (or fails). The callback is called from the worker-thread. In the callback you should\nreturn immediately, and do any time-consuming processing in another thread. \n\nSince all IO happens in the worker-thread, no data synchronization should normally be required, \nleading to better performance and simpler code. \n\n## Example from a real app\n\nHere is a method called when a user click on a button in an IOS or Android app using this library.\nIt's called from the UI thread and returns immediately. The lambda function body is called from \na worker-thread.\n\n```C++\nvoid AccountImpl::getBalance(IAccount::balance_callback_t callback) const {\n        curl_.Build()-\u003eGet(getServerUrl())\n            .BasicAuthentication(getHttpAuthName(), getHttpAuthPasswd())\n            .Trace(APP_CURL_VERBOSE)\n            .Option(CURLOPT_SSL_VERIFYPEER, 0L)\n            .AcceptJson()\n            .WithCompletion([this, callback](const restincurl::Result\u0026 result) {\n                if (result.curl_code == 0 \u0026\u0026 result.http_response_code == 200) {\n                    LFLOG_IFALL_DEBUG(\"Fetched balance: \" \u003c\u003c result.body);\n                    if (callback) {\n                        LFLOG_IFALL_DEBUG(\"Calling callback\");\n                        callback(result.body, {});\n                        LFLOG_IFALL_DEBUG(\"Callback was called OK\");\n                    } else {\n                        LFLOG_ERROR \u003c\u003c \"No callback to call\";\n                    }\n                } else {\n                    // Failed.\n                    LFLOG_ERROR \u003c\u003c \"Failed to fetch balance. http code: \" \u003c\u003c result.http_response_code\n                        \u003c\u003c \", error reason: \" \u003c\u003c result.msg\n                        \u003c\u003c \", payload: \" \u003c\u003c result.body;\n                    if (callback) {\n                        LFLOG_IFALL_DEBUG(\"Calling callback\");\n                        callback({}, assign(result, result.body));\n                        LFLOG_IFALL_DEBUG(\"Callback was called OK\");\n                    } else {\n                        LFLOG_ERROR \u003c\u003c \"No callback to call\";\n                    }\n                    return;\n                }\n            })\n            .Execute();\n    }\n```\n\nThe code above use the [logfault](https://github.com/jgaa/logfault) C++ header only log-library.\n\n## More examples\n\nHere is a [test-app](tests/app_test.cpp), doing one request from main()\n\nThe [test-cases](tests/general_tests.cpp) shows most of the features in use.\n\n## Logging\n\nLogging is essential for debugging applications. For normal applications, you can normally\nget away with logging to standard output or standard error. On mobile, things are little more\ninvolved. Android has it's own weird logging library for NDK projects, and IOS has it's own \nlogging methods that are not even exposed to C++! \n\nRESTinCurl has a very simple logging feature that can write logs to std::clog, syslog or \nAndroid's `__android_log_write()`. It may be all you need to debug your REST requests. \n\nJust `#define RESTINCURL_ENABLE_DEFAULT_LOGGER 1` to enable it.\n\nIf you want to use the Android NDK logger, also `#define RESTINCURL_USE_ANDROID_NDK_LOG`. \n\nIf you want to use syslog, also `#define RESTINCURL_USE_SYSLOG`.\n\n\n**Logfault**\n\nIf you want full support for log files, IOS/Macos logging, Android, Syslog etc, you can \nget the [logfault](https://github.com/jgaa/logfault) C++ header only log-library, and \n`#include \"logfault/logfault.h\"` before you `#include \"restincurl/restincurl.h\"`. \nRESTinCurl will detect that you use logfault and adapt automatically. \n\n**Other log libraries**\n\nRESTinCurl use two macros, `RESTINCURL_LOG(...)` and `RESTINCURL_LOG_TRACE(...)` to generate log\ncontent. If you use another log library, or your own logging functions, you can define those two\nmacros to fit your needs. You can examine the code for the default implementation in `restincurl.h`\nto see how that can be done. Hint: It's simple. \n\n## Todo's\n- [x] Ensure thread safety with OpenSSL\n- [ ] Validate OpenSSL therad safety\n- [x] Make some sort of timer, so that we clean up and stop the thread after #time\n- [x] Make sure connection re-use it utilized\n- [x] Queue new requests if we reach RESTINCURL_MAX_CONNECTIONS concurrent connections\n- [x] Write complete documentation\n- [x] Write tutorial\n- [x] Test cases for non-async mode (RESTINCURL_ENABLE_ASYNC=0)\n- [ ] CloseWhenFinished() must allow new requests to enter the queue and to be completed\n- [ ] Verify that DELETE is implemented correctly.\n- [ ] Add correctly encoded query parameters from the RequestBuilder\n- [ ] Port to windows\n- [ ] Set up CI with some tests on Ububtu LTS, Debian Stable, Windows, macos\n- [ ] Add Android to CI\n- [ ] Add IOS to CI\n\n\n## Further reading\n\n- You may want to look at the [tutorial](https://github.com/jgaa/RESTinCurl/blob/master/doc/tutorial.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjgaa%2Frestincurl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjgaa%2Frestincurl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjgaa%2Frestincurl/lists"}