cpr is a modern HTTP library for C++, built for people.
This project is maintained by Fabian Sauter and Tim Stack
C++ Requests is designed to be as simple and pleasant to use as possible. HTTP method invocations through the primary API are short-lived and stateless – this library firmly believes that Resource Acquisition Is Initialization. Cleanup is as easy and intuitive as letting an object fall out of scope. You won’t find any init()
or close()
methods here, and proper use of this library requires neither delete
nor free
.
In cpr, options are actually options so if you don’t set them they’ll default to sensible values. This is facilitated by the keyword args-like interface:
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"},
cpr::Parameters{{"hello", "world"}}); // Url object before Parameters
is exactly identical to
cpr::Response r = cpr::Get(cpr::Parameters{{"hello", "world"}},
cpr::Url{"http://www.httpbin.org/get"}); // Parameters object before Url
That is, the order of options is totally arbitrary, you can place them wherever you want and the outgoing call is the same. And that’s pretty much it! Of course, there are lots of different ways to configure your requests, but by design they’re all accessed through the same simple interface.
Making a GET request with cpr is effortless:
#include <cpr/cpr.h> // Make sure this header is available in your include path
// Somewhere else
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"});
A cpr::Url
object can also be created using std::string_view
instead of std::string
as parameter.
This gives us a Response
object which we’ve called r
. There’s a lot of good stuff in there:
std::cout << r.url << std::endl; // http://www.httpbin.org/get
std::cout << r.status_code << std::endl; // 200
std::cout << r.header["content-type"] << std::endl; // application/json
std::cout << r.text << std::endl;
/*
* {
* "args": {},
* "headers": {
* ..
* },
* "url": "http://httpbin.org/get"
* }
*/
To add URL-encoded parameters, throw in a Parameters
object to the Get
call:
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"},
cpr::Parameters{{"hello", "world"}});
std::cout << r.url << std::endl; // http://www.httpbin.org/get?hello=world
std::cout << r.text << std::endl;
/*
* {
* "args": {
* "hello": "world"
* },
* "headers": {
* ..
* },
* "url": "http://httpbin.org/get?hello=world"
* }
*/
Parameters
is an object with a map-like interface. You can construct it using a list of key/value pairs inside the Get
method or have it outlive Get
by constructing it outside:
// Constructing it in place
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"},
cpr::Parameters{{"hello", "world"}, {"stay", "cool"}});
std::cout << r.url << std::endl; // http://www.httpbin.org/get?hello=world&stay=cool
std::cout << r.text << std::endl;
/*
* {
* "args": {
* "hello": "world"
* "stay": "cool"
* },
* "headers": {
* ..
* },
* "url": "http://httpbin.org/get?hello=world&stay=cool"
* }
*/
// Constructing it outside
cpr::Parameters parameters = cpr::Parameters{{"hello", "world"}, {"stay", "cool"}};
cpr::Response r_outside = cpr::Get(cpr::Url{"http://www.httpbin.org/get"}, parameters);
std::cout << r_outside.url << std::endl; // http://www.httpbin.org/get?hello=world&stay=cool
std::cout << r_outside.text << std::endl; // Same text response as above
A lot of the examples so far have constructed the option objects inside the method call, but there’s no restriction on where those objects come from. The library is smart enough to know when it has to copy an argument and when it can safely move the object from the call site.
Making a POST request is just as easy as a GET request:
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Payload{{"key", "value"}});
std::cout << r.text << std::endl;
/*
* {
* "args": {},
* "data": "",
* "files": {},
* "form": {
* "key": "value"
* },
* "headers": {
* ..
* "Content-Type": "application/x-www-form-urlencoded",
* ..
* },
* "json": null,
* "url": "http://www.httpbin.org/post"
* }
*/
This sends up "key=value"
as a "x-www-form-urlencoded"
pair in the POST request. To send data raw and unencoded, use Body
which takes std::string
or std::string_view
as parameter instead of Payload
:
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Body{"This is raw POST data"},
cpr::Header{{"Content-Type", "text/plain"}});
std::cout << r.text << std::endl;
/*
* {
* "args": {},
* "data": "This is raw POST data",
* "files": {},
* "form": {},
* "headers": {
* ..
* "Content-Type": "text/plain",
* ..
* },
* "json": null,
* "url": "http://www.httpbin.org/post"
* }
*/
Here you will notice that the "Content-Type"
is being set explicitly to "text/plain"
. This is because by default, "x-www-form-urlencoded"
is used for raw data POSTs. For cases where the data being sent up is small, either "x-www-form-urlencoded"
or "text/plain"
is suitable. If the data package is large or contains a file, it’s more appropriate to use a Multipart
upload:
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Multipart{{"key", "large value"},
{"name", cpr::File{"path-to-file"}}});
std::cout << r.text << std::endl;
/*
* {
* "args": {},
* "data": "",
* "files": {
* "name": <contents of file>
* },
* "form": {
* "key": "large value"
* },
* "headers": {
* ..
* "Content-Type": "multipart/form-data; boundary=--------------33b210e9d7b8bd02",
* ..
* },
* "json": null,
* "url": "http://www.httpbin.org/post"
* }
*/
Notice how the "Content-Type"
in the return header is different now; it’s "multipart/form-data"
as opposed to "x-www-form-urlencoded"
. This facilitates larger and more generic data uploads with POST.
Uploading a file or files using Muitipart
sets the uploaded "filename"
to it’s path name by default.
To change this, you can override the "filename"
for the uploaded file:
// The uploaded file is named "path-to-file"
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Multipart{{"part-name", cpr::File{"path-to-file"}}});
// The uploaded file is named "new-file-name"
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Multipart{{"part-name", cpr::File{"path-to-file", "new-file-name"}}});
// The uploaded files are named "path-to-file1" and "path-to-file2"
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Multipart{{"part-name", cpr::Files{"path-to-file1", "path-to-file2"}}});
// The uploaded files are named "new-file-name1" and "new-file-name2"
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Multipart{{"part-name", cpr::Files{
File{"path-to-file1", "new-file-name1"},
File{"path-to-file2", "new-file-name2"},
}}});
It is also possible to pass a buffer instead of a filename, if the file’s content is already in memory.
// STL containers like vector, string, etc.
std::vector<char> content{'t', 'e', 's', 't'};
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Multipart{{"key", "large value"},
{"name", cpr::Buffer{content.begin(), content.end(), "filename.txt"}}});
// C-style pointers
const char *content = "test";
int length = 4;
cpr::Response r = cpr::Post(cpr::Url{"http://www.httpbin.org/post"},
cpr::Multipart{{"key", "large value"},
{"name", cpr::Buffer{content, content + length, "filename.txt"}}});
Any self-respecting networking library should have support for authentication. It’s rare for a web API to allow unfettered access to the datasets they guard. Most often they require a username/password pair:
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/basic-auth/user/pass"},
cpr::Authentication{"user", "pass", cpr::AuthMode::BASIC});
std::cout << r.text << std::endl;
/*
* {
* "authenticated": true,
* "user": "user"
* }
*/
This uses Basic Authentication. To use Digest Authentication, just use the DIGEST
authentication mode:
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/digest-auth/auth/user/pass"},
cpr::Authentication{"user", "pass", cpr::AuthMode::DIGEST});
std::cout << r.text << std::endl;
/*
* {
* "authenticated": true,
* "user": "user"
* }
*/
and like a good friend, cpr handles the negotiation for you. cpr::Authentication{"user", "pass", cpr::AuthMode::NTLM}
is also available for NTLM authentication.
Authentication via an OAuth - Bearer Token can be done using the Bearer
authentication object:
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/bearer"},
cpr::Bearer{"ACCESS_TOKEN"});
std::cout << r.text << std::endl;
/*
* {
* "authenticated": true,
* "token": "ACCESS_TOKEN"
* }
*/
Built in OAuth - Bearer Token authentication is available in case your libcurl
version is >= 7.61.0
.
For versions of libcurl
< 7.61.0
, you have to manipulate the header of your request manually.
#if CPR_LIBCURL_VERSION_NUM >= 0x073D00
// Perform the request like usually:
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/bearer"},
cpr::Bearer{"ACCESS_TOKEN"});
#else
// Manually add the Authorization header:
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/bearer"},
cpr::HeaderAuthorization);
#endif
std::cout << r.text << std::endl;
/*
* {
* "authenticated": true,
* "token": "ACCESS_TOKEN"
* }
*/
With these basic operations, modern C++ has access to a significant portion of the world wide web’s APIs. For more complex applications, check out the Advanced Usage guides.