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.

6 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

Leave a Reply

Your email address will not be published. Required fields are marked *

*

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> <pre lang="" line="" escaped="" highlight="">