REST – Can You do More than Spell It? Part 2

We interrupt our regularly scheduled series to bring you this article about Representational State Transfer, better known as REST. Yes, this is David Shirey’s series on the subject, but he’s graciously invited me to write this installment and share some insight into supporting REST requests in PHP.

In the first article of his series, David explained how REST is more than an architectural pattern. It’s a set of guiding principles that, if followed, can help you write scalable and robust applications. In the following articles, David will resume the discussion by looking at REST from the client-side of the equation. In this article though I’d like to focus on the server-side. You’ll learn how to shift your thinking from the action-focused mindset that’s prevalent in web development today to a more RESTful, resource oriented, approach, and see one way to structure your code and route URI requests in PHP.

Changing Your Mindset

The first thing you should do after making the decision to develop your application following the REST principles is to brainstorm a list of resources that will be made available.

An all-to-common way of thinking about web applications focuses on functionality. For example, a restaurant rating system written in PHP might have an editRestaurant.php script that presents a form to update an entry, and the form might submit to a script named saveRestaurant.php. Notice how the actions performed by the scripts are exposed as part of their file names. REST on the other-hand focuses on resources… in this case the restaurant post itself.

A user will still be able to create, view, and update resturant entries in a REST-based rating system, but just not through links like example.com/viewRestaurant.php?id=42. Instead, the post would be created by sending an HTTP POST request to example.com/restaurant, viewed by an HTTP GET to example.com/restaurant/42, and updated by an HTTP PUT to example.com/restaurant/42. Regardless if they are thick-client apps, web apps, mobile apps, or whatever else, all programs allow the users to accomplish tasks (actions). RESTful applications are no different, it’s just the core actions are pre-defined by the protocol in use. And since the actions are already defined, you’re free to focus on what the target resource of those actions will be (i.e. the restaurant).

At this point you should only be brainstorming the resources that are exposed to the user of the application, not necessarily the objects that make up your app. Continuing with the rating example, the system could have a User object to authenticate the application users, Restaurant and Comment objects for the restaurant and user-supplied comments, and maybe even a RestApp container object with static convenience methods (Restaurant App, REST App, see my pun there?). A user wouldn’t interact with these objects himself, though so they’re not categorized as resources.

The restaurant maintainer wants to write up information about the eatery and approve all the wonderful comments left by users; the reader wants to read reviews and leave comments. If you’re a Agile Development shop then you can probably glean a list of resources right from your user stories. Care to take a guess what the resources will be? Yep… you guessed it! A restaurant and a comment!

Mapping Resources: From URIs to Code

Most REST-focused code will probably employ some sort of resource mapping. This lets you have clean resource URLs and hide the actual architecture and implementation from your end users, a very good thing indeed!

A common practice is to route all requests to a central index or controller file, and then invoke the appropriate code logic from there depending on the requested resource and any parameters or properties of the request. If you’re using a LAMP stack, routing requests to a single entry point is as easy as enabling mod_rewrite, allowing htaccess overrides, and placing a .htaccess file in your web directory with the following:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php

All resources that map to an existing file (such as images, CSS files, etc.) are served directly by Apache. Otherwise the index.php file will be used.

For the sake of illustration, let’s say you have index.php, css/style.css, and img/logo.png in your web root directory. Apache would serve css/style.css in response to a request for example.com/css/style.css; img/logo.png would be served for example.com/img/logo.png; and Apache would invoke index.php to handle a request for example.com/restaurant and example.com/restaurant/42.

The index.php file needs to know through which URL it was reached through know what the user was really requesting, what PHP code in your application should be executed for the particular request, and what do to when the request cannot be satisfied.

The natural “hierarchy” that I’ve subtly used in my example URLs up until now (like www.example.com/restaurant/42) follows a pretty common pattern you’ll see in REST-based applications around the ‘net. The path of the URL (/restaurant/42) is easily parsable and understood as a request for a restaurant resource, and specifically the instance of a restaurant resource identified by the ID 42. Thus, the codebase could have a Restaurant class, an appropriate instance could be instantiated, and manipulated accordingly. For example:

<?php
// assume autoloader available and configured
$path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$path = trim($path, "/");
@list($resource, $params) = explode("/", $path, 2);

$resource = ucfirst(strtolower($resource));
$method = strtolower($_SERVER["REQUEST_METHOD"]);
$params = !empty($params) ? explode("/", $params) : array();

if (class_exists($resource)) {
    try {
        $resource = new $resource($params);
        $resource->{$method}();
    }
    catch (Exception $e) {
        header("HTTP/1.1 500 Internal Server Error");
    }
}
else {
    header("HTTP/1.1 404 File Not Found");
}

This simple example illustrates one way of parsing the URL’s path into a resource and its possible parameters, and then using that information to create an instance of the class with the same name as the resource. The parameters from the path are injected into the object through its constructor, and then the responsibility for handling the request is handed off to the object’s method by the same name as the HTTP method used to request it.

One drawback of the above code however is that you are limited to a shallow namespace hierarchy of objects. If you wish to pursue a dynamic dispatching mechanism like this, I suggest parsing the URI from right-to-left and testing whether a suitable class exists. This should allow you to have more depth in the hierarchy.

Representing Resources as Classes

The routing strategy you choose will affect how resource objects should be structured. The preceding routing code assumes the class will have post(), get(), put(), head(), etc. methods defined. Since all possible resource objects must follow this convention, it would be a good idea to define a master interface, a contract that promises an object will offer a specific API (and thus hopefully specific functionality).

You could also write an abstract class with a partial implementation of the standard methods. An abstract class cannot be instantiated on it’s own, and must be extended by a concrete class, but it helps you to avoid repetitive method definitions. With a little bit of reflection, a very powerful and robust base for other resource objects to build upon can be put in place.

<?php
abstract class Resource
{
    protected static $httpMethods = array("GET", "POST", "HEAD",
        "PUT", "OPTIONS", "DELETE", "TRACE", "CONNECT"); 

    protected $params;

    public function __construct(array $params) {
        $this->params = $params;
    }

    protected function allowedHttpMethods() {
        $myMethods = array();
        $r = new ReflectionClass($this);
        foreach ($r->getMethods(ReflectionMethod::IS_PUBLIC) as $rm) {
            $myMethods[] = strtoupper($rm->name);
        }
        return array_intersect(self::$httpMethods, $myMethods);

    }

    public function __call($method, $arguments) {
        header("HTTP/1.1 405 Method Not Allowed", true, 405);
        header("Allow: " . join($this->allowedHttpMethods(), ", "));
    }
}

The HTTP/1.1 spec says that a 405 code should be returned to the client if an unsupported request method is used, and that a list of valid methods should be returned as well. Suppose the example.com/restaurant resource should support GET and POST options, but obviously not ones like DELETE. The response to a DELETE request should look like this:

HTTP/1.1 405 Method Not Allowed
Allow: GET, POST

The abstract class uses the magic method __call() to catch any undefined object methods, and then uses reflection to determine the list of HTTP methods supported by the concrete class. The concrete class must have a public method by the same name as the HTTP method it handles for it to work… a palatable convention. The classes only need to implement such function/methods for the HTTP request methods they intend to support, and the error handling for unsupported requests is left up to the functionality encapsulated within the abstract parent.

A sample Restaurant class that extends Resource might then look like this:

<?php
class Restaurant extends Resource
{
    public function __construct($params) {
        parent::__construct($params);
    }

    public function get() {
        // logic to handle an HTTP GET request goes here
        // ...
    }

    public function post() {
        // logic to handle an HTTP POST request goes here
        // ...
    }
}

Closing Remarks

While REST is awesome, a purely REST-full approach may not be practical given user expectations on the web. The world has grown up with a forced RPC-style paradigm on top of HTTP, and we’re stuck with it now; that’s what people expect. They want a pretty login page, log in/out functionality, etc. which makes no sense in the world of REST. Remember, all information the server needs to satisfy a request must accompany that request; server-side sessions and tracking logins/logouts don’t fit the REST paradigm.

That’s not to say your REST-based projects have to be insecure; strategies exist like HTTP AUTH, DIGEST AUTH, etc. which permit user credentials to accompany the request. I’m merely saying its best to understand the benefits and the limitations of REST and apply it to projects that make the most sense. Instead of websites, REST-full systems tend to be web services like the Atom Publishing Protocol for publishing blog posts, or APIs like the one exposed by CouchDB.

We now return you to your regularly scheduled series, already in progress. :)

Image via littlesam / Shutterstock

Win an Annual Membership to Learnable,

SitePoint's Learning Platform

  • blacksonic

    REST is a good thing but the practices u use in this article may be harmful for beginners
    1. use of error supression operator
    2. using input string unmodified to determine which class to use

    • http://zaemis.blogspot.com Timothy Boronczyk

      Thanks blacksonic; avoiding the suppression operator and not trusting user input are both best-practices. But here, these shortcuts allowed me to present a minimum amount of code to convey a particular concept.

      The suppression operator is used to prevent a possible undefined offset warning being generated when $path is split and stored into its constituent parts but when $path doesn’t contain a slash. The end result will be that either $resource will hold the first part or all of the path to map against the resource controller, and $params will contain the rest of the path or be null to be used as additional arguments passed into the resource controller. This particular case using the suppression operator allowed me to guarantee both $resource and $params will always be initialized (also a good practice).

      While $_SERVER["REQUEST_URI"] contains user-provided data, again in this particular instance not filtering it before calling parse_url() isn’t much of a security risk. In the case of malformed input, parse_url() would simply pass the value on as the PHP_URL_PATH, list/explode() would put the value in $path, and then class_exists() would fail. class_exists() acts the validation/filter point that guarantees the input is appropriate. In a worst case scenario there is no risk and the user simply receives a 404.

      I think with you bringing up the point and me explaining my thought process while writing the code, I can let the article stand but readers will still have enough information to help them make informed decisions when writing their own production code. Thanks!

      • blacksonic

        it might encourage novices to use error suppression elsewhere also
        i consider error supression nearly as evil as eval…my best is: @eval(‘some code here’)

  • Alex Gervasio

    Despite the error suppression/request URI filtering issues, both of which have been extensively clarified above (btw, I don’t think this might impact negatively in the mindset of novices reading this, so please let’s no be so frantic about it), the article is a nifty gem. Not only it unveils in a clear and concise way the logic standing behind REST, but it shows how to create a functional REST controller, including the handling of a typical request/route/dispatch/response cycle in less than 30 locs.
    Nicely done Tim!

  • Attila Fulop

    Great article. I would be eager to read more about REST topics:
    – Best practices of authentication.
    – API keys vs user/pass.
    – Using https when requests ship between two php applications.

    Thanks again, keep up! :)