nemetral.net | Insightful posts on design and code

June 25, 2008 · Category Webdev · icon0

The pursuit of APIness (part 3)

This article was written by nemetral.

Voices matter! Please feel free to share your opinion, ask for more explanations or point out divergences using comments.

No time to read this now? Bookmark it and come back later..

In part 2, we saw how could be designed an XML-based API structure for fictitious website community.com allowing 3rd party developers to get access to members of a given age and living in a given city. The problem was: is it really a good idea to let every website or webapp design its own fancy API? It is now time to introduce the 3 main standard API structures: REST, XML-RPC and SOAP.

Part 3: Let’s take a REST

REST (REpresentational State Transfer) is actually more than a plain API structure. When coining this concept, Roy Fielding described an entire style of software architecture based on:

  • protocol constraints: the protocol has to be client-server, stateless, cacheable, layered and allowing code-on-demand
  • resources: resources are fundamental informational elements on which operations can be realized (representing, linking, modifying, including, searching, caching etc.)
  • universal syntax: resources are uniquely addressable using a universal syntax
  • representation: resources are not data and therefore need to be represented (through pictures, HTML or content of any kind)
  • uniform interface: the transfer of state is executed through well-defined operations and content-types

An good example of RESTful architecture is the World Wide Web: HTTP is client-server, cacheable, layered, stateless when used RESTfully (i.e. without cookies or sessions), able to carry code-on-demand (e.g. JavaScript or Java applets) and accesses resources through a uniform interface (HTTP methods such as GET/POST/PUT/DELETE, MIME content-types, headers and URIs). Still, HTTP can be used more or less RESTfully and we can imagine other RESTful architectures than HTTP.

Let’s now apply the REST principles to the code snippets we have written in part 2. A RESTful API doesn’t have to comply with a given XML format but with an architectural style. So here is how we could rewrite our API call in a RESTful manner, i.e. using the full potential or URIs and HTTP methods:

GET /members?age=23&city=Indianapolis HTTP/1.1
Host: api.community.com

As you can see, the URL has changed: we are no longer POSTing XML to an opaque “submit” resource but rather calling a meaningful “members” resource using the GET HTTP method and specifying meaningful parameters directly in the URL.

HTTP/1.1 200 OK
Date: Tue, 17 Jun 2008 20:24:00 GMT
Content-Length: 85
Content-Type: application/text-xml

<?xml version="1.0" encoding="UTF-8"?>
  <data>
    <name>Anna</name>
    <name>Lisa</name>
  </data>

The response format does not need to change: as we’ve seen, REST doesn’t define a XML format but gives general principles of architectural design.

Programmatically speaking, there is little change in the script consuming the web service (we’re still using PHP, cURL and SimpleXML). This is what our code would look like:

<?php

  // STEP 1: SEND THE REQUEST
  $url = 'http://api.community.com/members?age=23&city=Indianapolis';
  $handle = curl_init();
  curl_setopt($handle, CURLOPT_URL, $url);
  curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1);
  $response = curl_exec($handle);
  curl_close($handle);

  // STEP 2: PARSE THE RESULT AND DISPLAY THE NAMES
  if ($response) {
    $result = new SimpleXMLElement($response);
    $val = array();
    foreach ($result->name as $name) {
      $val[] = (string) $name;
    }
    print_r($values);
  } else {
      echo "An error occurred.";
  }

?>

Note: in case the parameters you provide to the URL have special caracters you need to urlencode() them. Also, note that we have added a condition to check the response before looping through it.

Let’s now have a look at the script providing the web service; here is an example of how the REST call could be handled (assuming the script name is members.php, located in /scripts and accessible through Apache URL rewriting):

RewriteEngine on
RewriteRule ^members(.*)$ scripts/members.php$1

And now the script:

<?php

  $connection = mysql_connect('host', 'user', 'password');
  mysql_select_db('database', $connection);

  $age = $_GET['age'];
  $city = $_GET['city'];
  if (!is_int($age) || !is_string($city)) {
    header('HTTP/1.1 400 Bad Request');
    exit();
  } else {
    $query = 'SELECT name FROM members WHERE age=' . $age .
             ' AND city=' . $city;
    $data = mysql_query($query);
    $members = array();
    header('Content-Type: application/text-xml');
    echo "<data>";
    while ($item = mysql_fetch_array($data)) {
      echo "<name>" . $item['name'] . </name>;
    }
    echo "</data>";
  }

?>

In a nutshell, here is why this rewritten script is more RESTful:

  • we consume the web service through a GET parameter calling a meaningful members resources and specifying meaningful parameters right in the request URI
  • in case there is an error (e.g. incorrect data for the age parameter), we use a dedicated HTTP status to carry the error message instead of adding a layer of XML in the response

The most important thing to remember about REST is that it’s only a set of architectural recommandations. Next week we’ll have a look at another API standard focusing on the XML message format more than the general architecture: XML-RPC.

(go to Part 4: Review of XML-RPC)

Entries (RSS) Did you enjoy this post? Consider subscribing to the RSS feed!

Leave a comment