Chapter 5. JSON

JSON stands for JavaScript Object Notation, but don’t be fooled by the name. Although it sounds as if it’s a JavaScript-specific format, it is supported by most programming languages today. It’s a very simple, lightweight format, which can represent nested, structured data.

For example, consider a data set that looked like this:

  • message

    • en: “hello friend”

    • es: “hola amigo”

In JSON, that data would look like this:

{"message":{"en":"hello friend","es":"hola amigo"}}

If a piece of data is represented by a scalar value, then it is presented plainly. If it is structured (as shown in the previous example), such as an associative array or an object with properties in PHP, a curly brace is used to indicate a new level of depth in the data structure. The keys and values are separated by colons, and each record at a given level is separated with a comma.

It is also possible to show a list of items quite elegantly using JSON. Take this imaginary shopping list:

  • eggs

  • bread

  • milk

  • bananas

  • bacon

  • cheese

A JSON representation of this would simply be:

["eggs","bread","milk","bananas","bacon","cheese"]

As you can see here, many of the keys in the previous example are optional, and multiple values are enclosed with the simple square brackets. If this list was in fact the value of a property, then both kinds of brackets would be seen:

{"list":["eggs","bread","milk","bananas","bacon","cheese"]}

This example shows that our data contained a key/value pair, with the key “list.”

When to Choose JSON

JSON gives a very clear indication of the original data structure and conveys the values within, but doesn’t give us any specific information about the exact data types that were originally in use. Often, this isn’t important; HTTP is entirely string-based anyway so it is usual to deal with this type of data in web-based applications.

JSON’s strongest point is that it is a simple data format. It doesn’t take much storage space in comparison to XML and isn’t too large to transfer “over the wire” or, in the case of mobile applications, over a potentially slow and patchy data connection! Since it is quite small and simple, it is inexpensive in processor terms to decode the JSON format, which makes it ideal for less powerful devices such as phones.

Use JSON when information about the exact data format isn’t critical, and the effort needed to decode it must stay light. It’s great for casual web or mobile applications—and of course it’s absolutely ideal if you are supplying data to a JavaScript consumer, since it handles this data format natively and quickly.

Content negotiation over HTTP using headers has already been covered earlier in the book (see Chapter 3); this is how it is ascertained that the client would like a JSON response format. As an example, here are the headers for a request/response pair in which the consumer is requesting JSON and the API provides exactly that:

> GET /header.php HTTP/1.1
> Accept: application/json, text/html;=0.5

< HTTP/1.1 200 OK
< Content-Type: application/json

{"message":"hello there"}

You can see that the final entry in the example is the body of the response. The format of this is the same JSON that was covered earlier in this chapter. Setting the headers correctly is absolutely key, since without the correct Content-Type header, any application receiving this request will not know how to decode it. If it requested JSON, it might hope that’s what was returned, but the Content-Type should always match. If it isn’t specified, many web servers will default to sending a Content-Type of “text/html,” which is not only inaccurate, but also dangerous because a browser will try to display the content as HTML and allow embedded JavaScript—so do take care to set those headers correctly.

Handling JSON with PHP

This is very simple, which is another reason to choose JSON as a preferred output format! In PHP, you can use json_encode() to turn either an array or an object into valid JSON.

For example, the previous example showed some JSON that looked like this:

{"message":"hello you"}

To generate that from PHP (which is exactly how I generated the previous examples), I simply used this line:

echo json_encode(array("message" => "hello you"));

This shows a very simple array wrapped in json_encode() and using echo to output it so I can see it when I request the page.

To handle incoming JSON data and turn it into a structure you can use, simply use json_decode(), passing the string containing the JSON as the first argument. Sticking with our existing simple example, the code could look something like this:

$data = json_decode('{"message":"hello you"}');
var_dump($data);

This example includes var_dump() to show exactly what actually happens when the json_decode() function is used: by default, an object is returned. Here’s the output of that script:

object(stdClass)#1 (1) {
  ["message"]=>
  string(9) "hello you"
}

Because there is no data-type information, JSON cannot tell whether this was an array with keys and values, or an object with properties, before it was turned into JSON; there is no difference between the two. We would get identical output from a script that looked like this instead:

$obj = new stdClass();
$obj->message = "hello you";
echo json_encode($obj) . "
";

Similarly, the same output would be shown if an object of any other class were used; the object-type information just isn’t included in JSON so it can’t be retrieved at the other end. When calling the json_decode(), it is possible to convert the data to an associative array rather than an object—by passing true as the optional second argument:

$data = json_decode('{"message":"hello you"}', true);
var_dump($data);

This time around, our output is subtly different:

array(1) {
  ["message"]=>
  string(9) "hello you"
}

Whether you choose to work with objects or arrays is up to you, and really depends on the application and also the language. Since there’s no object-type information stored in JSON, the object produced by json_decode() is always StdClass and personally I find it easier to take an array and possibly hydrate a specific object type with that data.

The JSONSerializable Interface

PHP also offers a way of describing how an existing object will behave when passed json_encode(), which is a useful technique if you’re outputting data that exists as an object in your application before it is output. It uses an interface called JSONSerializable; your object should implement this interface and include the jsonSerialize() method. This method will be called when the object is converted to JSON.

Here’s a simple example, starting with a very basic class that just adds the interface and defines what to do, then shows it in action:

<?php

class gardenObject implements JsonSerializable
{
  public function jsonSerialize() {
    unset($this->herbs);
    return $this;
  }
}

$garden = new gardenObject();
$garden->flowers = array("clematis", "geranium", "hydrangea");
$garden->herbs = array("mint", "sage", "chives", "rosemary");
$garden->fruit = array("apple", "rhubarb");

echo json_encode($garden);

// {"flowers":["clematis","geranium","hydrangea"],"fruit":["apple","rhubarb"]}

This can be a very useful shortcut to quickly convert an object even if it needs a little customization before output.

Consuming JSON APIs

As an example of working with an API that uses JSON, let’s take a look at a little piece of the GitHub API and use JSON for our examples. The examples here work with gists, which are similar to “pastebins”—places where you can put code or other text to share with others.

Our example is very simple; we make a POST request and include some JSON in the body of the request. A POST request usually creates data, as you’ll see in Chapter 8, and in this case we’re creating a new gist:

<?php

// grab the access token from an external file to avoid oversharing
require("github-creds.php");

$data = json_encode([
    'description' => 'Gist created by API',
    'public' => 'true',
    'files' => [
        'text.txt' => [ 'content' => 'Some riveting text' ]
    ]
]);

$url = "https://api.github.com/gists";
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER,
    ['Content-Type: application/javascript',
  'Authorization: token ' . $access_token,
  'User-Agent: php-curl']
);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);

$gist = json_decode($result, true);
if($gist) {
    echo "Your gist is at " . $gist['html_url'];
}

There are a few things going on here that bear closer examination: sending JSON in requests, working with an Authorization header, and using credentials to gain access. You will notice that a variable $access_token is referenced, which isn’t set in the code. This is set in the github-creds.php file and kept separate to stop access keys from being leaked in this text. In a real development project, I’d still keep this separate, but for a different reason—using a separate file means I can exclude it from source control and avoid publicizing my access keys to the world! Of course it does happen, and if it does, you can always revoke your token and generate a new one. If you ever suspect that a token has been leaked, then do destroy it and generate another (something to bear in mind if your tokens are visible when demonstrating APIs).

A POST request is used to create a new gist (GitHub has a RESTful API) and send JSON-formatted data along with it. In fact, this is a PHP array (because those are easy to understand and work with), which is then converted to JSON using json_encode(). The resulting output is given as the value for CURLOPT_POSTFIELDS and PHP sends it as the body of the request.

This example also sets some headers using the CURLOPT_HTTPHEADER option. The first one is Content-Type, which we have already seen in many examples, and the second one is Authorization. The Authorization header here includes the “token” and the access token within it, because the GitHub API uses OAuth2 for authorization. We discussed OAuth in Chapter 3. The GitHub API also requires that a User-Agent header be sent so you will need to include this too if your PHP isn’t already configured to send it by default.

If all goes well with the previous request, a 201 status code will arrive with the response and the new gist will be created. The gist will also be visible on the Web. Alternatively, the gist can be requested over the API: one of the things included in the response when requesting the new gist is a link to it, so we can extend the example to also fetch the gist. Since this is a public gist, no authorization is needed and it is possible to just grab the data using file_get_contents(), then json_decode() it. You could add the following code to the previous example to do exactly this:

if($gist) {
    echo file_get_contents($gist['url']);
}

You can easily try this yourself, or for an even simpler way to interact with the GitHub API, simply request all your own gists using https://api.github.com/users/username/gists and replacing username with your own GitHub username. Many APIs use JSON in a similar way to exchange information with consumers, and you’ve now seen how to do that with PHP.

In addition to working purely with PHP, when working with JSON APIs you may find yourself wanting to construct, inspect, and otherwise manipulate JSON data. There are some tools we will discuss later in Chapter 11, notably jq and the Python json module, that can help with this task.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset