Fork me on GitHub
Logo

cpr - C++ Requests

cpr is a modern HTTP library for C++, built for people.

User Guide

This project is maintained by Fabian Sauter and Tim Stack

Design

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.

GET Requests

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.

POST Requests

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"}}});

Authentication

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.