In the first part of this blog post we’ve talked about the theory behind REST services. In this post we put the theory into practice with the help of some code snippets you can implement in your own application.

So how exactly do we put everything in practice? We go through the code step by step, but we assume you have a sort-of working Zend application and enough knowledge on Zend Framework. Overall it’s not really that hard.

Create a REST controller

All our functionality is hidden behind our own REST controller. This controller is extended from Zend_Controller_Action. This is done because in our project either a complete controller is REST or it isn’t. There is no mixture between REST and non-REST actions. When you need a simple REST-action then this setup might not be the best case for you. For now, we use the “all actions in controller are REST enabled”-rule.

The only thing we need to add is an additional init() method where we initialize the context-switch.

Create the REST contextswitch helper

The REST contextswitch helper is not that much different as the normal context switch helper. In fact: you could use the normal contextswitcher without any problem. If you have worked with the contextswitch helper, you might have noticed some differences.

As stated earlier, we want all our actions in the REST controllers to be context-aware. We could achieve this during initialization of the controller where we add each action to the context-switcher. This is pretty dull and error-prone work. Instead, we override the getActionContexts(), hasActionContext() and addActionContext() methods. The getActionContext() is called by ZF to decide which context it needs to display, so it would need to return the same context for all actions. The hasActionContext() always returns true, since all actions have a context and addActionContext() must be overridden by a method that will trigger an exception. We cannot use this method for adding contexts, since it would mean we add a context per action. Instead, we must use a new method called addGlobalContext(), which adds a global context, and it’s this context that always gets returned by getActionContext().

Still on our todo list is to implement removeGlobalContext() to, well, remove the global context, and removeActionContext(), which also should trigger an exception. Consider this homework for you as a reader to implement. :)

Furthermore: we need to add a small block of code in the initContext() function: When we don’t have a context, we must add the default context. In order to do this we must copy/paste the whole initContext() block. :( It’s exactly what we wanted to avoid when using an OO setup.

Create an accept-handler plugin

Now the controller is completely finished and we can move on to the plugins. We need  some functionality that actually decides what format we need to use. This is done with our accept-handler plugin. This controller-plugin simply implements the routeShutdown() method, but there are some small catches though:

First, we don’t always have an HTTP request. This happens when we call the controller through a CLI SAPI for example. In that case we just return.

Next, we need to set the “Vary” flag in the response. See the first blog post about why this is needed (hint: caching).

The plugin self is nothing more than a parsing of the “Accept”-header and setting the ‘format’ parameter. This way we can control the contextswitch either by Zend’s original contextswitch or by our rest-contex switcher. That’s the only job this plugin must do: set the request’s format-parameter based on the accept-header.

The HTTP_HEADER_APPLICATION_TYPE is a constant that points to the vendor-string:

application/vnd.com.enrise.rest

which means our clients can use context switch through the HTTP fields:

Accept: application/vnd.com.enrise.rest+json; version: 1.0;
Accept: application/vnd.com.enrise.rest+xml; version: 1.0;
etc..

Create a media-format plugin

Another thing we must do: check if we are actually allowed to view the given context. It might be possible that we don’t accept all contexts on all occasions. For instance, we accept JSON and XML output on production but not HTML output. On a development system, we like to have HTML output, because that would make our life easier.

We could build the “check” into the accept-handler, but we’ve decided we wanted a separate place for that. There are some additional reasons we need this separate, but has no influence for the scope of this blog.

But before we can check what formats are allowed, we need to define them. Our application.ini is a good place for that:

We now know our formats so we can create a simple plugin that fetches the formats and compares them with our current “format” parameter from the request. If it doesn’t match, we are requesting a “forbidden” or unknown format. We should respond with a HTTP 415 (Media type not supported) status code.

That’s it.. make sure though you add the plugins to your front-controller inside your application.ini:

resources.frontController.plugins[] = "Service_Controller_Plugin_AcceptHandler"
resources.frontController.plugins[] = "Service_Controller_Plugin_Mediaformat"

Conclusion

Doing REST and doing REST right are two completely different things. REST isn’t easy, it just looks that way. Versioning, HATEOAS, stateless resources and actions are much more difficult to implement as you might think. However, with the help of the Zend Framework and some custom code you can come a long way..

About Joshua Thijssen

Joshua Thijssen is a senior software engineer at Enrise and owner of the privately held company NoxLogic. His daily work consists of maintaining code bases, working on different projects and helping other to achieve higher standards in both coding and thinking.

His passion lies in high-end and complex internet systems and clusters, code optimization, server administration and fine-tuning. His programming skills includes (but is not limited to) assembly, C, C++, Java, Perl, Python and PHP and has experience on a wide range of operating systems. One of his specialties is fine tuning MySQL databases and queries.

His personal tech blog can be found on http://www.adayinthelifeof.nl

Zend Certified Engineer PHP5 Zend Certified Engineer PHP5.3 Zend Framework Certified Engineer MySQL Certificate Database Developer MySQL Certificate Database Administrator

Leave a Reply

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

One thought on “REST Style context switching – part 2

  1. We found that if you don’t use the Zend_View component when outputing json or xml is a gain of performance. Most of the time you can just serialize some model record and send it via the json helper like $this->getHelp(‘json’)->sendJson($model->toArray());

Volg ons

Twitter

Douglas Crockford opening the #zendcon closing keynote talking about the Dutch genius Edsger Dijkstra! http://t.co/yK9FSTarPn
- Thursday Oct 30 - 6:53pm

Meet the Zend team! #zendcon http://t.co/lM5qrkgqCl
- Thursday Oct 30 - 2:50am

. @EvanDotPro is sharing very useful and detailed info about #nginx and configuring it for performance! #zendcon http://t.co/gXmBxJnAsf
- Wednesday Oct 29 - 11:26pm

After the panel discussion about #bitcoin, at 2:45pm @jrvandijk will be talking about our experience with Zend Server in room 204! #zendcon
- Wednesday Oct 29 - 8:39pm

Synthetic benchmarks from PHP over the years. 5.6 is about 6x faster then 4.4. #zendcon http://t.co/RZCt0ISTVV
- Wednesday Oct 29 - 4:51pm