

In the previous article in this series, we learned how the CakePHP routing system handles URLs and interacts with your application in order to dispatch requests to the proper controller action. In the first article of the series, we saw how the Router's features could be combined with other classes in the framework (the , for example) to enable things like unifying the handling of different resource types.We're going to take these concepts further and add a new one: REST.
In the previous article in this series, we learned how the CakePHP routing system handles URLs and interacts with your application in order to dispatch requests to the proper controller action. In the first article of the series, we saw how the Router's features could be combined with other classes in the framework (the RequestHandler, for example) to enable things like unifying the handling of different resource types.
We're going to take these concepts further and add a new one: REST. In the course of this series so far, we've only been discussing how to use the Router to examine and act on different parts of a URL. However, the URL is not the only piece of information we're concerned with when a client is making an HTTP request. Along with a URL that defines what an HTTP client is requesting, the client also sends headers, which help you determine all sorts of useful details, like what kind of information the client is sending, and what it expects back.
We are able to use these headers in order to implicitly handle various aspects of a client's request that might otherwise require extra user input or programmatic configuration from people using our site or service. As a refresher, here a few of the more useful ones:
application/x-www-form-urlencoded. If the client submits XML data, however, the value may be text/xml or application/xml, or content-type of a more specific XML dialect, like application/atom+xml.By wrapping array keys in the second parameter with square brackets, it is possible to create routes which respond based on certain HTTP headers and server environment variables. When writing routes, you can use any server variable that starts with HTTP_, as well as several custom ones: type (maps to CONTENT_TYPE), method (maps to REQUEST_METHOD), and server (maps to SERVER_NAME). Any HTTP server variables are used lowercase and without the HTTP_ prefix; i.e. HTTP_ACCEPT_LANGUAGE becomes accept_language.
There are many possible ways in which to leverage this, including automatically localizing content, detect supported encodings and automatically compressing data streams, and determining how to handle incoming POST and PUT data.
For purposes of this tutorial, the principal header of interest is REQUEST_METHOD, as it enables the Router to map HTTP verbs to controller actions. Now, you could specify one route (like the above) for each HTTP verb, but the Router provides you with a handy wrapper method to wire them all up at once.
This will map the following requests to the corresponding controller actions, as follows:
GET /posts: PostsController::index()
GET /posts/5: PostsController::view(5)
POST /posts: PostsController::add()
PUT /posts/5: PostsController::edit(5)
DELETE /posts/5: PostsController::delete(5)
POST /posts/5: PostsController::edit(5)
REQUEST_METHOD header, Cake takes into account the X_HTTP_METHOD_OVERRIDE header, as well as a POST variable called _method. Either of these can be used to enable proper REST support in a web browser (the POST variable, being more explicit, takes precedence).Now that REST handling has been mapped, we can move on to using it to manage domain objects as full-blown HTTP resources. Referring back to previous articles in the series, add the following:
Again, this tells the Router to recognize and parse file extensions in URLs.
Also from previous examples, this is used in the controller to handle template switching, and setting the proper response headers based on the custom extension. Now that this is set up, we can begin serving resources in multiple representations. Consider the following example:
Using this setup, templates for content types like XML can easily be added as follows:
As you can see, simply creating templates in a subdirectory of the views folder, named according to the file extension, it is now possible to serve XML content for the index() view. You'll note that the view is using a helper called $xml, which wasn't specified in the controller.
When serving custom content types, the RequestHandler checks to see if there are any helpers corresponding to that type. Since the CakePHP core includes XmlHelper, is is automatically added to the list of helpers loaded in the view. The record output is then passed to it, and the helper renders it as a set of XML tags. Nothing to it. In fact, the view for the view() action is almost the same:
Except in this case the <posts /> wrapper tags are not needed, since there is already only one root node in the document.
When it comes to the edit action, things get more complicated, since there is also input to be handled. Since an XML interface is being provided, it's only natural for clients to want to send XML to do updates. This is where another bit of RequestHandler magic comes it. After examining the content-type of the incoming POST or PUT request, if it is an XML type, then the input is taken and passed to an instance of Cake's Xml object, which is assigned to the $data property of the controller. Since Cake Models already know how to speak Xml object, handling XML and POST data in parallel is seamless: no changes are required to the controller or model code.
By following the same model as the RequestHandler, you can write your own components to automatically transform input content to a format that Cake can handle, thereby abstracting that logic away from the rest of your application.
Using these techniques, you're well on your way to fully REST-API-enabling your applications on CakePHP.
Brilliant.

