Advertisement

Demystifying REST

by

No, this is not an article that encourages you to sleep more! However, if that was your first inclination, then the following text was tailor-made for you! It’s an unfortunate truth, though, that the principles of REST are decidely complex. Entire books have been written on the subject. I won’t be so presumptuous to assume that I can merge such an intricate topic into a few thousand words.

That said, REST, like some other technologies, such as Git and CSS, is one in which a bit of understanding will take you a long way. To move as quickly as possible, this article will focus less on the history and philosophy behind REST (as well as how it differs from other technologies, like SOAP), and more on the practical aspects. How can you implement the REST architecture today?


What is REST?

Hold on there, partner. Before we can jump into some code examples, we should first discuss what REST, or Representational State Transfer, refers to.

REST, defined over a decade ago by Roy Fielding in his doctoral dissertation, provides a simple way to organize interactions between systems, most frequently through HTTP and the web browser. In hindsight, this cohesion makes perfect sense: Roy is also one of the principle authors of HTTP!

Let’s discuss URIs for a moment. A URI is essentially an identifier for a resource. Consider the following example:

GET /friends

We could call this a resource. When this route is triggered, following the REST pattern, all friends should be fetched, presumably from a database, and presented.

But, how might we specify a request for just one friend? How about:

GET /friends/joe

Readable, isn’t it? That’s one of the key components to a RESTful architecture. It allows for URI structures, which are equally readable by both humans and machines.

Think of a resource as a plural noun. Contacts, statuses, users, photos - all of these would be perfect choices.

So far, we have hooks to identify a collection, as well as a single element within that collection:

/friends  
/friends/joe

In fact, you’ll find that these two segments are all that you should ever need! We can then leverage the power of HTTP to designate how the server should respond to these URIs. Let me explain:

Every HTTP request specifies a method, or verb, within the headers. You’re likely familiar with a couple of them, such as GET and POST. Perhaps an example is in order. Open Google Chrome, and browse to http://net.tutsplus.com. Next, open Chrome Developer Tools (via a right-click), and view the Network tab. You may potentially need to refresh the page to view the various assets that have been fetched. Select the first item in the list, and view the headers.

“Google Chrome’s developer tools can be used to, among other things, inspect the headers for a given request.”

Wait a minute; even though we didn’t specify it, the request method, GET, was automatically set! From this, we can deduce (dear Watson) that GET is the default verb, when viewing web pages.

For any given URI, we may reference four different request methods: GET, POST, PUT, and DELETE.

GET /friends  
POST /friends  
PUT /friends  
DELETE /friends

Essentially, these HTTP verbs instruct the server what to do with the data indentified by the URI. Still confused? You should be! An easy way to decipher these verbs is to compare them to the common CRUD acronym, or Create-Read-Update-Delete.

GET => READ  
POST => CREATE  
PUT => UPDATE  
DELETE => DELETE

We’ve established that GET is the default request method, but you’re certainly familiar with POST as well. Have you ever created an HTML form that, when submitted, POSTs the data to your server? Well, when that form submits, the request method being used is POST, not GET. As such, to, say, add a new status to a tweets table within your database, the form should POST to /tweets, rather than something along the lines of /tweets/addNewTweet.php.

In fact, a dead-ringer for a non-RESTful application is to search for verbs in the URI. The HTTP request method should define how the server should interact with the URI, not a mass of meaningless PHP files!

All of the following represent non-RESTful (and poorly designed) URIs.

/tweets/addNewTweet.php  
/friends/deleteFriendByName.php  
/contacts/updateContact.php

To channel my younger self, yuck! Don’t do this. However, this does raise the question: what would be the correct URI to present a form to a user, for the purposes of adding or editing a resource?

In these situations, it makes sense to add two more URIs.

GET /friends/new  
GET /friends/joe/edit

The first path, /friends/new, should present a form to the user to add a new friend. Upon the form’s submission, a POST request should be used, as we are adding a new friend.

For the second, /friends/joe/edit, this form should be used to edit an existing record within our database. When updating a resource, a PUT request is appropriate.

Wondering how to make PUT requests from an HTML form? Stay tuned.


Verbs

Before we move forward with some concrete code examples, let’s further solidify what each of these verbs represent.

GET

As noted previously, GET is the HTTP request method that we’re all most familiar with: the default verb. One caveat, or best practice, when it comes to GET requests, is that they should always be treated as safe and idempotent. In other words, a GET request should be “read-only.”

It’s important to note that, as the engineer, you’re free to do whatever you want, when these routes are triggered. Nothing prohibits you from modifying data on the server, when a GET request is triggered. It’s merely a best practice to refrain from doing so.

A safe method refers to one that will never modify a resource. The term, idempotent, refers to a method that will achieve the same result, regardless of how many times it is requested. GET, PUT, and DELETE request types are idempotent - that is, if you’re following the rules.

POST

The second request method that you’re likely familiar with is POST. These days, this type is most often used to designate when new data should be added to a resource. For example, when adding a new friend, a POST method would be the correct choice.

POST /friends

PUT

Traditionally, a PUT request should be used, when you need to either create or update a resource. However, perhaps the result of Ruby on Rails conventions, in most modern web applications, PUT is used exclusively for updating a resource.

Let’s imagine that we need to update the age of our friend, Joe. Upon updating his information, via a form, the correct request method would be, PUT.

DELETE

As you might have guessed, DELETE should be used, when you need to delete the resource identified by a particular URI.

If we’re no longer friends with Susan, following the principles of REST, she can be destroyed, via a DELETE request.

DELETE /friends/susan

Once executed, all data associated with Susan should be removed from the database.


Implementation

All of this theory is great, but, ultimately, it’s useless, if we don’t understand how to apply this architecture to our projects. Well, there’s a few ways. In the following section, we’ll use the popular Slim PHP framework to organize the necessary routing, however, you’ll surely find that most frameworks these days include some form of RESTful integration, including Ruby on Rails and Laravel.

To make use of Slim, the first step is to install it through Composer.

“Composer is a tool for dependency management in PHP. It allows you to declare the dependent libraries your project needs and it will install them in your project for you.

Wait, you’re not familiar with Composer? Stop what you’re doing right now and research it. Composer allows us to leverage the PHP community, by specifying and installing packages that an application requires. No more reinventing the wheel!

Installing Composer globally only requires two quick commands.

$ curl -s https://getcomposer.org/installer | php
$ sudo mv composer.phar /usr/local/bin/composer

That’s it! You now have access to the composer command.

The next step is to specify Slim as a required package for your app. This can be accomplished, via a composer.json file within the root of your project.

{  
    "require": {  
        "slim/slim": "2.*"
    }
}

With this requirement set, we only need to run composer install to download the necessary dependencies. Easy!

Thanks to a few lines of code - and the PHP community - we now have an elegant way to register routes. Here’s a simple example, which you can place within index.php.

<?php  

require 'vendor/autoload.php';  

$app = new \Slim\Slim();  

$app->get('/friends', function() {  
    echo 'Fetching all friends';  
});  

$app->run();

Remember: all of this functionality comes free of charge!

“Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs.

Let’s now setup the necessary resourceful routes. We’ll opt for simple echo statements to describe what sort of action should be executed in a real-world application.

<?php  

// Use Composer's built-in autoloader  
require 'vendor/autoload.php';  

$app = new \Slim\Slim();  

$app->get('/friends', function() {  
    echo 'Fetch all friends';  
});  

$app->get('/friends/new', function() {  
    echo 'Show form to add a new friend';  
    // Form should post to /friends  
});  

$app->get('/friends/:friend', function($friend) {  
    echo 'Show single friend: ' . $friend;  
});  

$app->get('/friends/:friend/edit', function($friend) {  
    echo 'Show form to edit friend'  
    // Form should put to /friends/$friend  
});  

$app->;post('/friends', function() {  
    echo 'Add a new friend';  
});  

$app->;put('/friends/:friend', function($friend) {  
    echo 'Update friend';  
});  

$app->;delete('/friends/:friend', function($friend) {  
    echo 'Delete friend';  
});  

$app->;run();

When using Slim, we can specify the request method that we wish to respond to, using $app->VERB. As such, to delete the friend, Joe, we’d listen for a delete request to /friends/joe, like so:

$app->delete('/friends/:friend', function($friend) {  
    echo 'Destroy friend';  
});

Testing Routes

If you’re like me, your next thought might relate to how you’re supposed to test PUT and DELETE methods. As you might know, most browsers only natively provide support for GET and POST. Making use of the other two request methods requires a bit of trickery, which we’ll review shortly.

Until then, the most user-friendly way to make custom requests is through a Google Chrome extension, called Advanced Rest Client. Once installed, you can easily specify both a URI, as well as the desired request method.

“The Advanced REST Client extensions provides an easy mechanism to test URIs.

cURL

If you’re somewhat comfortable in the command line, it’s recommended that you instead leverage the power of cURL to test these routes.

curl localhost:8888/friends -X GET

the X flag allows you to specify the request method that should be used. Please note that, in the previous snippet, we’re being explicit; the X flag is not necessary for GET requests, as they are the default.

Here’s an example for testing a few routes. Keep in mind that we’re using simple echo statements to describe the action that should take place.

$ curl localhost:8888/friends -X GET  
Getting all friends

$ curl localhost:8888/friends -X POST -d 'name=Jane&amp;age=30'  
Add a new friend

$ curl localhost:8888/friends/jane -X PUT -d 'name=Jane&amp;age=28'  
Update friend, Jane

$ curl localhost:8888/friends/jane -X DELETE  
See ya, Jane

Modifying data on the server will surely require the new data (likely obtained from a form). When using cURL, key-value pairs may be specified, using the -d flag, like so:

$ curl localhost:8888/friends -X POST -d 'name=Jane&amp;age=30'

This command can be divided into three pieces:

  1. What’s the URI?
  2. What request method should be used?
  3. What data should be passed to the server?

Using your server-side language of choice (in our case, PHP), you can then fetch this POST data in the same way that you normally would:

$app->post('/friends', function() {  
    $name = $_POST['name']; // Jane  
    $age = (int) $_POST['age']; // 30  

    // Now, update the database  
});

Browser Support

Okay, we understand how to specify a request method from the command line, but how might we do the same thing from an HTML form? Unfortunately, we can’t rely on:

<form method="put">

Our current crop of browsers do not provide native support for these types of requests. The most common solution is to apply a bit of trickery, via hidden inputs. Using the Slim framework, here’s how we might update a friend.

<!-- /friends/susan/edit -->
<form action="/friends/susan" method="post">
  ... other form fields here...  
  <input type="hidden" name="_METHOD" value="PUT">
  <input type="submit" value="Update Susan">
</form>

Notice that, technically, the request method is still set to POST. However, behind the scenes, Slim will read the hidden input’s value, and proceed accordingly, dependent upon which verb is specified.

<input type="hidden" name="_METHOD" value="PUT">

You’ll certainly find that most frameworks follow a similar pattern for specifying request types.

In this section, we reviewed but one framework’s implementation of resourceful routing. As you’ll find, though, the same is possible in most frameworks these days. For example, if you’re a Laravel artisan, then you might use the following syntax (as of version 4):

Route::resource('friends', 'FriendsController');

This convenient resource method specifies that we wish to generate the necessary routes for a friends resource, and make FriendsController responsible for handling the logic for each of these routes.


Manual Implementation

Should you wish to opt out of a framework, you can still implement this functionality on your own. Unfortunately, writing the necessary routing system from scratch is beyond the scope of this tutorial, however, here’s a few tips to get you started.

First, the most important question: how do we determine what the associated verb for a particular request is? If working along, create a new PHP file, and add:

<?php  

echo $_SERVER['REQUEST_METHOD'];

If you run this page in the browser, the output should be GET. Excellent! Now, we have the necessary means to detect the request method, and proceed, as needed.

The following snippet is decidely elementary, and will require better structure for your projects, but it can be used as a starting point.

# What request method?  
$verb = $_SERVER['REQUEST_METHOD']; // GET

# What's the URI?  
$uri = substr($_SERVER['REQUEST_URI'], 1); // friends/joe

# Create an array of the segments  
$segments = explode('/', $uri); // ['friends', 'joe']

# Determine the controller name  
$controller = $segments[0]; // friends  

// Proceed as needed, based upon request type  
switch ($verb) {  
    case 'GET':  
    case 'POST':  
    case 'PUT':  
    case 'DELETE':
}

Testing

There are a variety of packages, which make the process of writing integration tests as simple as possible. However, let’s keep it simple and use PHP’s built-in cURL library (libcurl) to test some of these routes.

The first step would be to initialize cURL, and specify the desired URI. In our case, we’ll continue testing the friends resource.

# Init curl, and specify the URI  
$ch = curl_init('localhost:8888/friends');

Next, unless we’re testing the default GET request method, we’ll need to specify the request type.

# Specify HTTP verb (We'll ignore the data for now)  
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

By default, this output will immediately be echoed. To instead return the output to a variable, rather than displaying it directly, we can make use of the CURLOPT_RETURNTRANSFER setting.

// Return the output instead of displaying it directly  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

That should do it! We only need to execute the request, and fetch the results.

$response = curl_exec($ch); // Add a new friend  
$statusCode = curl_getinfo($ch)['http_code']; // 200

PHPUnit

Let’s add this to a PHPUnit test - again, keeping it relatively simple, for readability’s sake. We’ll simply ensure that each route returns the proper 200 status code, signifying that the request has completed successfully. To dry things up, we’ll abstract the cURL functionality away to its own method, request().

<?php // friendsTest.php  

class FriendsTest extends PHPUnit_Framework_TestCase {  
    protected $baseUrl = 'localhost:8888/';  

    public function testFriendsCollection()
    {  
        $request = $this->request('friends', 'GET');  
        $this->assertEquals('200', $request->statusCode);
    }  

    public function testUpdateFriend()
    {  
        $request = $this->request('friends/frank', 'PUT');  
        $this->assertEquals('200', $request->statusCode);
    }  

    protected function request($url, $verb = 'GET')
    {  
        $ch = curl_init($this->baseUrl . $url);  
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $verb);  
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $response = new stdClass;  
        $response->data = curl_exec($ch);  
        $response->statusCode = curl_getinfo($ch)['http_code'];

        return $response;
    }
}

Assuming that you have PHPUnit installed, run phpunit friendsTest.php. If successful, you should see green! Feel free to engage in a private victory dance.

To take things a step further, it makes sense to abstract that request method out to a base class that your tests can then extend. Or, even better, let a highly tested (and functional) third party tool handle the legwork. You might consider Goutte, which can be installed through Composer.

{  
    "require": {  
        "slim/slim": "2.*",  
        "fabpot/goutte": "1.0.*@dev"
    }
}

Once installed (composer install), we can ignore the manual cURL implementation from earlier, and instead make use of Goutte’s cleaner API, as demonstrated below:

<?php // friendsTest.php  

require 'vendor/autoload.php';  

use Goutte\Client;  

class FriendsTest extends PHPUnit_Framework_TestCase {  
    public function setUp()
    {  
        $this->client = new Client;
    }  

    public function testFriendsCollection()
    {  
        $this->client->request('GET', 'http://localhost:8888/friends');

        $response = $this->client->getResponse();

        $this->assertEquals('200', $response->getStatus());
    }  

    public function testAddFriend()
    {  
        $this->client->request('POST', 'http://localhost:8888/friends', []);

        $response = $this->client->getResponse();

        $this->assertEquals(200, $response->getStatus());
    }
}

You wouldn’t be the first person to consider such tests to be superfluous; however, I assure you that, as soon as one of these tests failing saves you from a silly blunder, you’ll instantly recognize their usefulness.


Further Learning

To continue your education, the best guide for learning REST comes courtesy of the folks at Apigee. Their presentation, “Teach a Dog to Rest,” compiles a mass of knowledge into a mere twenty minutes. This is required viewing for all beginners.

“Apigee offers one of the most user-friendly introductions to REST on the web.

Thanks for reading!

Advertisement