CakePHP RESTFul Routes – Basics

Introduction

In my opinion, CakePHP is a well equipped framework for building web applications. In this article I will try to explain how I overcame certain obstacles challenges when dealing with CakePHP and RESTFul Routes. For this article I used CakePHP v2.4.3 with a slight alteration to the core code => will be fixed in 2.4.4.

The table below shows a standard implementation for a projects controller in PHP with a RESTFul pattern as described in Ruby on Rails. This pattern will be the base for my own projects controller with the difference that I won’t be splitting the methods to show a form and to save a form but use the CakePHP Convention of capturing the request, execute logic and reply to the user if something worked or not. This makes it easier to handle data and send back error messages – if needed – without rerouting and storing input in extra sessions, which are obviously not available when an API has to work as a HTTP/cURL like service.

HTTP Verb Path Action Used for
GET /projects index display all projects
GET /projects/add new return a HTML Form to add a new project
POST /projects create create a new project
GET /projects/:id show display a specific project
GET /projects/:id/edit edit return a HTML Form to edit a project
PATCH/PUT /projects/:id update update a specific project
DELETE /projects/:id destroy delete a specific project

RESTFul Routes

The Implementation

CakePHP offers an “easy” RESTFul implementation out of the box. It works with the resourceMap below:


// File: app/config/routes.php
[..]
/**
 * Setup new Default Resource Map for "correct" RESTFul routes.
 * You don't have to do this because these are the default
 * resourceMap routes.
 */
    Router::resourceMap( array(
        array( 'action' => 'index', 'method' => 'GET', 'id' => false ),
        array( 'action' => 'view', 'method' => 'GET', 'id' => true ),
        array( 'action' => 'add', 'method' => 'POST', 'id' => false),
        array( 'action' => 'edit', 'method' => 'PUT', 'id' => true ),
        array( 'action' => 'delete', 'method' => 'DELETE', 'id' => true ),
    ) );

/**    
 * map controller resources
 */
    Router::mapResources( 'projects' );
    Router::mapResources( 'phases' );
    Router::mapResources( 'tasks' );
    Router::mapResources( 'activities' );
    Router::mapResources( 'users' );
[..]
/**
 * Load the CakePHP default routes. Only remove this if you do not want to use
 * the built-in default routes.
 */
    require CAKE . 'Config' . DS . 'routes.php';

Parse url with JSON extension

I forgot to mention that what I am trying to create must be accessible via an app – in my case an android app, therefore I enabled a feature that parses a URL with a JSON extension like “http://my.website.com/projects.json” to the right controller and action inside my web application. It’s as easy as pie Cake(PHP)!


// File: app/config/routes.php
[..]
/**
 * Parse JSON Views when using .json extension
 */
    Router::parseExtensions( 'json' );
[..]
/**
 * Load the CakePHP default routes. Only remove this if you do not want to use
 * the built-in default routes.
 */
    require CAKE . 'Config' . DS . 'routes.php';

Update the controller

To let your Controller know that you want to work with the JSON extension and generate JSONized output, follow these steps:

  • Open all desired controllers you want to edit
    

    • If you want all your controllers to be accessible via the .json extensions, only edit your AppController.php file.
  • Add the public array variable $components – if not already present, otherwise just append – and give it a value of array( 'RequestHandler');
  • For every method inside your controllers you might have already set view variables like so:

$this->set('projects', $projects);

To automatically return JSONized data as content add this to your method logic:


$this->set('_serialize', array( 'projects' ) );
  • Access your controller method with a .json extension to test if it worked and you’re done.

Using a prefix in a mapped resource

If you want to use a prefix with a resourceMap, visit this github commit alteration of the current CakePHP branch (2.4.3) to see what I changed in the core files – doesn’t have to apply to other cake versions. Without the addition the prefix method doesn’t work as you would expect.

To use a prefix in your url of a mapped resource like http://my.website.com/prefix/controller/action try the following code, where projects obviously is the name of your controller just like before.


Router::mapResources( 'projects', array( 'prefix' => 'api' ) );

This gives you a nice looking url like http://my.website/api/projects which indistinctly says “I’m the API, feed me with your data!! NOM NOM”. There are a few side-effects of this alteration of your code however. See if you can find out what they are and how you can work your way around them.

Conclusion

I believe that is all I wanted/needed to cover about the basics of RESTFul Routes in CakePHP. Next time I hope I have some information on how to handle validation with true RESTFul routes. A message system with Status codes (JSONized) would be a good idea, wouldn’t it? But that’s something for next time. Live long and prosper.