Channels ▼
RSS

Web Development

JSON and the Microsoft C++ REST SDK


The code simply creates an instance of json::value and then assigns values to each key. For example, the following line assigns a "Mobile" value to the "Title" key. Notice that it is necessary to specify the type for the value.

  obj[L"Title"] = json::value::string(U("Mobile"));

Then, the code creates an instance of utility::stringstream_t (stream) and passes it as an argument to the serialize method of the json::value instance (obj). This way, the code writes the current JSON value to a stream with the native platform character width and then displays in the console.

  utility::stringstream_t stream;
  obj.serialize(stream);

The resulting serialized JSON is:

  {"Title":"Mobile","Subtitle":"Mobile Developer","Description":"Mobile feature articles","MainPage":"mobile","Items":null,"Id":"2"}

The following lines show another version of the CreateAndDisplayJSONObject method that creates an array of items, adds an item to it, and then assigns it as the value for the Items key of the group. As you will notice, creating arrays is really simplified.

void CreateAndDisplayJSONObject()
{
	// Create a JSON object (the group)
	json::value group;
	group[L"Title"] = json::value::string(U("Mobile"));
	group[L"Subtitle"] = json::value::string(U("Mobile Developer"));
	group[L"Description"] = json::value::string(U("Mobile feature articles"));
	group[L"MainPage"] = json::value::string(U("mobile"));
	group[L"Id"] = json::value::string(U("2"));

	// Create a JSON object (the item)
	json::value item;
	item[L"Title"] = json::value::string(U("Developing Android Apps with Scala and Scaloid: Part 2"));
	item[L"Subtitle"] = json::value::string(U("Developing Android Apps with Scala and Scaloid: Part 2"));
	item[L"Description"] = json::value::string(U("Starting with templates, Android features can be added quickly with a single line of DSL code."));
	item[L"MainPage"] = json::value::string(U("mobile/developing-android-apps-with-scala-and-s/240162204"));
	item[L"Id"] = json::value::string(U("240162204"));

	// Create the items array
	json::value items;
	items[0] = item;
	
	// Assign the items array as the value for the Items key
	group[L"Items"] = items;

	// Write the current JSON value to a stream with the native platform character width
	utility::stringstream_t stream;
	group.serialize(stream);

	// Display the string stream
	std::wcout &;t;&;t; stream.str();
}

Here is the resulting serialized JSON:

  {"Title":"Mobile","Subtitle":"Mobile Developer","Description":"Mobile feature articles","MainPage":"mobile","Id":"2","Items":[{"Title":"Developing Android Apps with Scala and Scaloid: Part 2","Subtitle":"Developing Android Apps with Scala and Scaloid: Part 2","Description":"Starting with templates, Android features can be added quickly with a single line of DSL code.","MainPage":"mobile/developing-android-apps-with-scala-and-s/240162204","Id":"240162204"}]}

Figure 2 shows how you can inspect the values for the different variables of this method in the Locals window in Visual Studio 2013. It isn't as simple as you can debug with JavaScript when you create JSON content, but once you get used to the way the C++ REST SDK works, you can really boost your productivity in C++ compared with using C-based APIs.

[Click image to view at full size]

Figure 2: The Locals window in Visual Studio 2013 displaying the values and types for the different local variables of the CreateAndDisplayJSONObject.

Working with Asynchronous Streams

The C++ standard library provides useful synchronous streams.The Microsoft C++ REST SDK provides asynchronous streams that resemble those included in the C++ standard template library (STL). It also includes specific Interop Streams that support interoperability between STL iostreams and C++ REST SDK asynchronous streams.

The following lines show a sample HTTPReadInputStreamAsync method that retrieves a concurrency::streams::istream to read the first 1,000 characters from it and displays the results in the console. The code retrieves the first 1,000 characters from http://www.drdobbs.com/mobile.

pplx::task<size_t> HTTPReadInputStreamAsync()
{
	// I want to make the following HTTP GET: http://www.drdobbs.com/mobile
	http_client client(U("http://www.drdobbs.com"));


	// Manually build up an HTTP request
	http_request request(methods::GET);
	request.set_request_uri(U("mobile"));

	return client
		.request(request)
		// The following code executes when the response is available
		.then([](http_response response) -> pplx::task<size_t>
		{
			if (response.status_code() != status_codes::OK)
			{
				// Something went wrong and it is necessary to add some error handling code
				return pplx::task_from_result<size_t>(0);
			}

			istream bodyInputStream = response.body();
			container_buffer<std::string> inputStringBuffer;
			return bodyInputStream.read(inputStringBuffer, 1000)
				// The following code executes after reading the 1000 characters
				.then([inputStringBuffer](size_t bytesRead) -> size_t
				{
					const std::string &readText = inputStringBuffer.collection();
					std::wcout << readText.c_str();

					return bytesRead;
			});
		});
} 

The following line shows a blocking call to the previous method that retrieves the number of bytes read from the response:

  auto size = HTTPReadInputStreamAsync().get();

First, the HTTPReadInputStreamAsync method creates a new instance of the web::http::client:http_client class to maintain a connection with the base URI http://www.drdobbs.com. Then, the method manually builds up an HTTP GET request that sets the request URI to mobile. This way, the HTTP GET request will be made to http://www.drdobbs.com/mobile.

  http_client client(U("http://www.drdobbs.com"));
  http_request request(methods::GET);
  request.set_request_uri(U("mobile"));

The following lines show the initial code that makes the request and returns the resulting task instance that represents the asynchronous operation, as happened in the other examples. The request method uses the previously built http_request instance (request) as an argument. The then method adds a continuation task to the task that executes the request. This task receives an http_response instance (response) and returns a pplx::task<size_t>, i.e., a task that will return a size_t.

return client
	.request(request)
	.then([](http_response response) -> pplx::task<size_t>
	{
...

After the request is processed, the code after the then continuation is going to be executed in a new task. If the status code of the response isn't OK, the code returns the task created with pplx::task_from_result with 0 as an argument. Thus, the calling code will know that 0 bytes were read from the response. Naturally, additional error handling would be necessary.

  return pplx::task_from_result<size_t>(0);

If the status code of the response is OK, the code calls the response.body method that produces an input stream (a concurrency::streams::istream instance named bodyInputStream). Then, the code uses this input stream to retrieve data from the response in combination with a concurrency::streams::container_buffer<std::string> (inputStringBuffer). The container_buffer serves as a memory-based stream buffer that supports either writing or reading. The code returns the pplx::task<size_t> generated by the bodyStream.read method. This method reads up to 1,000 characters and places them into the provided buffer (inputStringBuffer). When the stream finishes reading the first 1,000 characters, a new task receives the input string buffer (inputStringBuffer) and the number of bytes read (bytesRead). The code in this task displays the input string buffer in the console and returns the number of bytes read (bytesRead).

.then([](http_response response) -> pplx::task<size_t>
{
	if (response.status_code() != status_codes::OK)
	{
		return pplx::task_from_result<size_t>(0);
	}

	istream bodyInputStream = response.body();
	container_buffer<std::string> inputStringBuffer;
	return bodyInputStream.read(inputStringBuffer, 1000)
		.then([inputStringBuffer](size_t bytesRead) -> size_t
		{
			const std::string &readText = inputStringBuffer.collection();
			std::wcout << readText.c_str();

			return bytesRead;
	});

Conclusion

The different chained asynchronous tasks are easy to understand by reading the code. You can read the code just as if you were working with synchronous methods.The C++ REST SDK makes smart use of C++ 11 features and the Microsoft Parallel Patterns Library. If you combine the C++ REST SDK with the Visual Studio 2013 async-aware debugging features, you can achieve great productivity levels accessing cloud services with C++. However, if you want to debug the asynchronous code that you write with the C++ REST SDK in previous Visual Studio versions, you won't enjoy the same benefits.


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

Related Article

Using 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.
 
Dr. Dobb's TV