Channels ▼
RSS

Using the Microsoft C++ REST SDK


Executing an Asynchronous HTTP GET Call with Parameters

The following code shows an example of a Windows console application that calls Flickr via the C++ REST SDK, using an HTTP GET call:

http://api.flickr.com/services/rest/?method=flickr.test.echo&name=value

and retrieve the status code returned by the server, the response headers type and length, and the response body. (Before using the code, you need to follow the steps explained in the previous section for your Visual Studio project.)

// The code includes the most frequently used includes necessary to work with C++ REST SDK
#include "cpprest/containerstream.h"
#include "cpprest/filestream.h"
#include "cpprest/http_client.h"
#include "cpprest/json.h"
#include "cpprest/producerconsumerstream.h"
#include <iostream>
#include <sstream>

using namespace ::pplx;
using namespace utility;
using namespace concurrency::streams;

using namespace web::http;
using namespace web::http::client;
using namespace web::json;

pplx::task<void> HTTPGetAsync()
{
	// I want to make the following HTTP GET: http://api.flickr.com/services/rest/?method=flickr.test.echo&name=value
	http_client client(U("http://api.flickr.com/services/rest/"));

	uri_builder builder;
	// Append the query parameters: ?method=flickr.test.echo&name=value
	builder.append_query(U("method"), U("flickr.test.echo"));
	builder.append_query(U("name"), U("value"));

	auto path_query_fragment = builder.to_string();
	
	// Make an HTTP GET request and asynchronously process the response
	return client.request(methods::GET, path_query_fragment).then([](http_response response)
	{
		// Display the status code that the server returned
		std::wostringstream stream;
		stream << L"Server returned returned status code " << response.status_code() << L'.' << std::endl;
		std::wcout << stream.str();

		stream.str(std::wstring());
		stream << L"Content type: " << response.headers().content_type() << std::endl;
		stream << L"Content length: " << response.headers().content_length() << L"bytes" << std::endl;
		std::wcout << stream.str();

		auto bodyStream = response.body();
		streams::stringstreambuf sbuffer;
		auto& target = sbuffer.collection();

		bodyStream.read_to_end(sbuffer).get();

		stream.str(std::wstring());
		stream << L"Response body: " << target.c_str();
		std::wcout << stream.str();
	});
}

#ifdef _MS_WINDOWS
int wmain(int argc, wchar_t *args[])
#else
int main(int argc, char *args[])
#endif
{
	std::wcout << L"Calling HTTPGetAsync..." << std::endl;
	// In this case, I call wait. However, you won’t usually want to wait for the asynchronous operations
	HTTPGetAsync().wait();

	return 0;
}
#ifdef _MS_WINDOWS
int wmain(int argc, wchar_t *args[])
#else
int main(int argc, char *args[])
#endif
{
	std::wcout << L"Calling HTTPGetAsync..." << std::endl;
       // In this case, I call wait. However, you won’t usually want to wait for the asynchronous operations
	HTTPGetAsync().wait();

	return 0;
}

The wmain method in Windows calls the HTTPGetAsync method that returns a pplx::task<void> instance that represents an asynchronous operation. In this case, the code calls the wait method for the returned task instance because the only goal for this sample console application is to display the results. However, you usually won't want to call wait for the returned task instance, so that you don't block the UI.

The HTTPGetAsync method creates a new instance of the web::http::client:http_client class to maintain a connection with the Flickr REST API whose base URI is http://api.flickr.com/services/rest/. The C++ REST SDK works with platform-independent strings, so in order to deal with string literals in a platform-specific way, the code uses the U(str) macro, which takes a string literal and produces the platform-specific type. The typedef utility::string_t corresponds to the platform preference.

http_client client(U("http://api.flickr.com/services/rest/"));

At this point, the code has the client and it is necessary to determine the relative URI that the request should use. The path is /services/rest and it is already included in the URI used to create the HTTP client. Therefore, there is no need to specify it. The code creates an instance of the web::http::uri::builder class that allows you to build URIs incrementally. It is a convenient way to append the query fragments in an elegant way (by using the U(str) macro). The two calls to the append_query method add the necessary queries to the URI builder, encoding them first. Then, the call to the to_string method for the builder generates the necessary query fragment to make the request.

uri_builder builder;
builder.append_query(U("method"), U("flickr.test.echo"));
builder.append_query(U("name"), U("value"));
auto path_query_fragment = builder.to_string();

The following lines show the initial code that makes the request and returns the resulting task instance representing the asynchronous operation. The request method indicates that it wants to make an HTTP GET request (methods::GET) and the query fragment that has to be added (path_query_fragment). Notice that the then method adds a continuation task to the task that executes the request. This way, the continuation task receives the http_response instance (response) as a parameter after the request is processed. Thus, the code after the then continuation is going to be executed in a new task and will check the results of the request. The code is easy to read, as if you were reading synchronous code. It is easy to see that the code block that appears after the then continuation is going to be executed after the request task finishes. You don't have to work with complicated futures, you can chain many tasks using the then continuation and adding the necessary code to be executed.

return client.request(methods::GET, path_query_fragment).then([](http_response response)
{
…
});

In this case, the code defined in the then continuation displays the status code returned by the server, the headers content type and length. Everything is easy to access by using the http_response received as a parameter (response) to the continuation task.

std::wostringstream stream;
std::wostringstream stream;
stream << L"Server returned returned status code " << response.status_code() << L'.' << std::endl;
std::wcout << stream.str();

stream.str(std::wstring());
stream << L"Content type: " << response.headers().content_type() << std::endl;
stream << L"Content length: " << response.headers().content_length() << L"bytes" << std::endl;
std::wcout << stream.str();

Here, the simple echo call to the Flickr API returns the following XML response. The example just wants to introduce how to build a simple HTTP GET request with parameters and process some results with the C++ REST SDK.

<rsp stat="fail">
    <err code="100" msg="Invalid API Key (Key has invalid format)"/>
</rsp>

The code that reads the response body uses a stream to retrieve the data from the incoming request. In this case, to keep things simple, the code calls the read_to_end method and then chains a call to the get method in order to wait for the results within the task in which the code is executing. The read_to_end method reads until reaching the end of the stream and returns a task<size_t> that contains The two files the number of characters read. Thus, you can call the read_to_end method with an asynchronous execution and chain another task to process the read results with the then continuation. In this case, the get method waits for the task to finish and returns the result that the task produced. Notice that when a task is canceled, a call to the get method will throw a task_canceled exception. You usually won't want to use get if you aren't within another task (so as to avoid blocking the UI).

auto bodyStream = response.body();
streams::stringstreambuf sbuffer;
auto& target = sbuffer.collection();

bodyStream.read_to_end(sbuffer).get();

stream.str(std::wstring());
stream << L"Response body: " << target.c_str();
std::wcout << stream.str();

As you can see from this example, executing a simple HTTP GET request with C++ 11 and the C++ REST SDK is fairly straightforward. The then continuation makes it simple to understand how asynchronous calls are chained and the different helpers included in the C++ REST SDK reduce the necessary boilerplate code to the minimum.

In the next article, I'll provide a complete example on how to retrieve and send JSON data with the C++ REST SDK, its helpers, and the typical chained asynchronous operations to the process as efficient as possible. In addition, I'll explain how to work with asynchronous streams and other HTTP methods usually required when interacting with REST services.


Gaston Hillar is a frequent contributor to Dr. Dobb's.

Related Article

JSON and the Microsoft C++ REST SDK


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video