Building A RESTful PHP Server: Routing the Request

This is the second part of a series, showing how you might write a RESTful API using PHP. This part covers the routing, autoloading, and controller code for the service, and follows on from the first installment which showed how to parse the incoming request to get all the information you need.

Routing to Controllers

In this setup, we'll have models, controllers and ... output handlers. It's not really a view, because all we will do is transform the data to a given output format. More on that later on - for now we will return the data we fetch in the controller back to index.php, and dump it out so we can inspect it.

For RESTful routing, each thing in the system is considered as a resource, and it has a unique resource identifier (or URI) to represent it. In this example system, we have users and groups. Each resource belongs to a collection, which is the level above the resource – I usually think of files being in directories when I think of resources belonging to collections.

So for an incoming GET request to /users, we will return a list of users as this is the collection. Within our application, this means calling the getAction() on the UsersController, so index.php now looks like this:

// route the request to the right place
$controller_name = ucfirst($url_elements[1]) . 'Controller';
if (class_exists($controller_name)) {
    $controller = new $controller_name();
    $action_name = strtolower($verb) . 'Action';
    $result = $controller->$action_name();
    print_r($result);
}

At this point, you'll write a controller and model that will look hauntingly familiar from all the other MVC systems you've ever written! Before we do that though, let's talk about architecture and autoloading.

Designing and Loading Classes

Working with classes gets much easier if you put them in reliable places and call them reliable names. If you do, you can autoload them and avoid all those tedious require() statements. My directory structure looks like this:

.
├── controllers
│   ├── MyController.php
│   └── UsersController.php
├── index.php
└── models

The users controller is in the controllers directory, and it inherits from a shared parent controller called MyController. I have no idea what will go into here, but from experience, I recommend that both models and controllers should inherit from a shared parent - as will our output handlers (because we don't have views) later on. You can see that the controllers are reliably found in the controllers directory, called something ending in *Controller.php. This makes it simple to add to an autoload rule: here's mine, which lives at the top of index.php:

spl_autoload_register('apiAutoload');
function apiAutoload($classname)
{
    if (preg_match('/[a-zA-Z]+Controller$/', $classname)) {
        include __DIR__ . '/controllers/' . $classname . '.php';
        return true;
    } elseif (preg_match('/[a-zA-Z]+Model$/', $classname)) {
        include __DIR__ . '/models/' . $classname . '.php';
        return true;
    } elseif (preg_match('/[a-zA-Z]+View$/', $classname)) {
        include __DIR__ . '/views/' . $classname . '.php';
        return true;
    }
}

Hopefully this is simple enough to follow; if the classname ends in "Controller", look in the controllers directory; if it ends in "Model" look in the ... you get the picture. Using very predictable naming and an autoload means that PHP will always find our classes easily (and we'll find them too when we are maintaining the system).

The RESTful Controller

This section is the part where you already know all you need to know! At least, if you've used MVC before, and you've ever written a controller, then the controller in your RESTful application will look a lot like the one in any other! It will talk to the model to fetch data, get everything in order and then pass it all on to a view.

In a RESTful system, the view is replaced by an output handler, so our controller will get everything assembled into an array and return it instead. Our controllers deal with a variety of HTTP verbs, but will also need to parse out nested records. Here's a super-simple example:

class UsersController extends MyController
{
    public function getAction($request) {
        if(isset($request->url_elements[2])) {
            $user_id = (int)$request->url_elements[2];
            if(isset($request->url_elements[3])) {
                switch($request->url_elements[3]) {
                case 'friends':
                    $data["message"] = "user " . $user_id . "has many friends";
                    break;
                default:
                    // do nothing, this is not a supported action
                    break;
            } else {
                $data["message"] = "here is the info for user " . $user_id;
            }
        } else {
            $data["message"] = "you want a list of users";
        }
        return $data;
    }
 
    public function postAction($request) {
        $data = $request->parameters;
        $data['message'] = "This data was submitted";
        return $data;
    }
}

In the getAction() we show some handling of requesting specifc resources and elements within those as well as just the collection; there is a very simple postAction() shown here too and the postAction() and deleteAction() would follow the same themes. You would only declare all of these if you want to actually support those actions over your API. For example, you might choose not to allow edit or delete of records, depending on your application.

At the moment, you have a working system, although all it does is print_r() the data it finds. The next installment of the tutorial will deal with output handlers and how to send well-formatted data in a RESTful response.

Edit: You can read the third entry in the series here.

17 thoughts on “Building A RESTful PHP Server: Routing the Request

  1. Hi Lorna,
    just a simple wp editor question: how do you manage to 'type' the tree structure for the files and folders, do you use a plugin or something? (for the part Designing and Loading Classes)

    Btw nice series, keep'em coming :)

    Thanks,
    //Wasseem

  2. Pingback: Lorna Mitchell’s Blog: Building A RESTful PHP Server: Routing the Request | Scripting4You Blog

  3. Pingback: Building A RESTful PHP Server: Understanding the Request | LornaJane

  4. Nice article, precisely shows how easy it is to come up with restful api server using PHP

    I have taken similar approach to create Restler framework that takes public methods of your classes and exposes them as RESTful api with various formats including JSON, XML, AMF, Binany Plist, XML Plist, YAML, JSONP etc

    Check it out and let me know what you think!

  5. Hi Lorna,

    I am wrestling with how to deal with nested resources. I understand your simple example above and from what I gather, the resource structure would look something like this to get the user's friends:
    /user/123/friends/

    So what happens if you want to even dig deeper?

    /user/123/friend/1231/cats/

    Do you just have to build for this? I can't think of an intuitive way to address this unless the cats becomes a filter inside a query string? I was reading somewhere else that it's also unnecessary to have many nested levels because you can just get these nested resources with an id but it's also my understanding with rest that it's meant to handle nested resources no matter how deep?

    What do you think?

    • Each of the friends is themselves a user. So the collection is /user/123/friends but it contains individual user resources such as /user/456 and user/789. So probably the cats collection for that user would be at /user/456/cats/

      Does that make some sense?

      • Yes, actually, that probably wasn't a good example. I guess I was trying to think of a scenario where there might be nested resources that are more than 2 levels deep like 3 or 5 levels. For example,
        /foos/222/bars/222/wizards/23423/

        Perhaps I am thinking about this too hard and it's very unlikely this would happen?

        I also have a few other questions...
        Q1. Is it better to use plural for the naming convention of these resources, so for example, /users/123/images/452?

        Q2. Is it better to build for different ways of capturing this information in the uri? So for example, /users/123/images/452, which returns image 452

        or

        /images/452

        Q3. I am trying to come to grips with how I would model these resources and which models would be returned/used. If someone enters /users/452/images, I imagine an images collection returns and it uses 452 as the ID to get these images? So in effect, it uses the id before images to find the collection vs. /users/452/images/192 that returns a single image model which uses 192 as the id?

        Cheers!

        • I still think that even in your deeply nested example, each bar and wizard would have their own URI which wasn't nested.

          Q1: singular or plural doesn't matter but be consistent. I find plurals work well grammatically.

          Q2: /images/452 for the individual image, probably /users/123/images for all the images for that particular user.

          Q3: yes :) I often use a basic MVC approach, such as in the open source joind.in API, which you can find the code for here: https://github.com/joindin/joind.in/tree/master/src/api-v2

  6. Hi, awesome article!
    But I would like to ask, where to insert the function apiAutoload? You have written that into the index.php. Does it mean that before the Request class? Thanks for your response.

    • Yeah the autoload setup has to go as early as possible - so that it knows how to load your Request class when you need it, and all your other classes.

  7. Hi, I would like to ask - Is this PHP server applicable also for different devices? For example, can Android mobile devices communicate with this kind of PHP server?

    • Absolutely! The joy of APIs is that to communicate with these systems, a client just needs to understand HTTP. The majority of APIs that I build for clients are consumed by mobile applications such as android devices, that's a really good example.

  8. Nice tutorial!! I'm new to REST and MVC and this helped me a lot. So as I understand it, for a simple GET request I can just use the URL to figure out which records(s) I grab and the JSON data really doesn't play any role. Therefore in an AJAX GET call, I don't need to pass any parameters but just tweak the url based on the request. The same would be true for a DELETE operation. For POST and PUTS I need to grab the JSON to get the individual field information. This probably seems like a redundant question, but I want to make sure that I have the basics straight before moving on. Thanks, Nick

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>