Quick Start Your REST Client with CppREST

Online services are getting more and more popular as the demand grows exponentially. Millions of connected devices already take advantage of cloud and edge services using REST. Representational State Transfer is a highly scalable and easy to use API protocol. In this post you will find the details for building your very simple C++ client that talks to any RESTful service using Microsoft’s C++REST library.

Operations on REST Services

Since REST provides full functional API to its clients for accessing, creating and manipulating data, it is not easy to cover all the details. So let’s focus on some basics. A RESTful API server provides GET, POST, PUT, PATCH, DELETE methods (and more). I will build my tutorial around Reqres mock server to demonstrate several functions.

Accessing the Data with GET

Not different than HTTP, GET method accesses the data on the server. Since REST server keeps data separately under different paths, issuing GET on the desired path will bring the data. Let’s try this endpoint first https://reqres.in/api/users that brings us the following JSON populated with fake users.

Depending on the server implementation and the context itself, it is also possible to filter the data using different path. As an example https://reqres.in/api/users/1 brings us the user with id 1 alone.

The same data can be requested with also using the query https://reqres.in/api/users?id=1. Another useful query is for paging https://reqres.in/api/users?page=1.

Creating New Data with POST

To create a new user, POST new user details to the endpoint https://reqres.in/api/users in JSON format. Server will respond 201 with the newly created user data including the assigned unique id.

Updating/Editing with PUT or PATCH

There are two different ways of changing data on the server. If we send the data as JSON including all the required fields (just like creating a new data) the server will overwrite the data at https://reqres.in/api/users/1, notice the user id appended in the end. The server will respond 200 with the following. If the user with id 1 does not exist, it may be created instead of updating.

Other option is making PATCH request with incomplete fields. It is useful if the data size is large and we don’t want to send the fields that we don’t want to change. The only difference to PUT is that the data to be patched must exist on the server.

Deleting Data with DELETE

Finally, it is very easy to delete an entry. Make a DELETE request to the correct endpoint with the desired id https://reqres.in/api/users/1 and the record will be deleted. Usually 204 is responded with no content.

For more information on the operations refer to this website.

REST Client Implementation in C++

Implementing your native client is not extremely hard but don’t invent the wheel again. CppREST (a.k.a. Casablanca) provides a nice experience for C++ that has everything you need in one place.

Development Environment

For this simple demo code, I’m using Visual Studio 2017 with cpprestsdk.v141 package installed via NuGet and dialect is C++17. I recommend the same since this is the least painful way to take-off. All the code explained in this post is also pushed to GitHub, feel free to use it.

Making GET Request

Writing to File

Although it is not the easiest one, I will start with the same example code that CppREST wiki provides. Try this code on a new project to see if your environment works fine.

Here are many things to explain. First of all, CppREST uses a concurrency framework named PPLX (a version of PPL) that starts parallel threads in the background and runs the tasks as programmed. I.e. fstream::open_ostream(U("users.json")) creates a PPLX task that will open a file stream and will return the stream object on exit. Later we define the next step using .then(...) method that gets the return value of the previous task and passes to the callable object (i.e. lambda expression). We can create a chain of operations that needs to be done in order and PPLX will take care of it in the background for us.

We have two options to keep track of the concurrent operation. We can use wait()  method that will block the current caller thread until the concurrent task is finished or we can poll the task using is_done() before getting the return value using get()  method (more information is here).

If everything is smooth, you will see the downloaded users.json file on your disk.

Parsing the JSON Response

As a more common use case, we can interpret the response which is in JSON format.

The code above successfully brings the user data and prints George Bluth (1) . Be careful about the strings when using C++REST sdk since it always uses unicode instead of std::string. Both the keys and values of JSON objects must be in U("...") format.

Making POST Request

This part gets tricky since we have to provide the details for a new user. We can create our user with json::value() and set the corresponding keys. Finally we will add the serialized json to the request body.

After this task finishes executing, we can see atakan sarioglu (999) on stdout. Server return code is 201 which means CREATED. Note that we used pplx::create_task(...) in order to create the JSON object before making the request.

Updating Data on Endpoint

Full Update with PUT

Now all we have to do is sending a new user with the PUT request. The mock server will act as if the data is modified but don’t forget that it is volatile.

On the console, atakan istanbul should be displayed.

Partial Update with PATCH

Similarly the following code is for PATCH request.

Observe {"name":"sarioglu","updatedAt":"2019-01-01T01:01:01.000Z"} on the output.

Making DEL Request

The simplest operation is DELETE which corresponds to DEL in C++REST SDK.

When server returns with 204, there is no content, means DEL is successful. On error we could get 404.

Conclusion

REST is an important tool and CppREST collects many nice tools in one place which brings a lot of comfort. However, a disadvantage is that it enforces wide strings (on windows) even when your implementation does not need it. Another problem arises in case of inappropriate using directives since C++REST redefines some STL elements i.e. Concurrency::streams::fstream is ambiguous to std::fstream.

Have a REST until the next post 😴