RESTful webservice using Zend Framework

Intro

Webservices are more and more used these days because of the way they decouple the service consumers by the service itself. It is very common for a (web)application to have a webservice that holds the business logic while the consumers use it through an API. The consumers could be a site or one or more mobile applications for handhelded devices.

As opposed to SOAP and/or RPC counterparts, where dedicated libraries are needed to work with each one of them, a pure RESTful webservice requires only a HTTP library in order to be used. It can be basically used from almost any programming language, mobile device or anything that has a HTTP library shipped along with.

Let’s take an example: imagine that you have an application that needs to manage an entity called “artists”.  Like you would think, the user (of your application) needs to fetch a full list of artists, to view details for a specific one, to create a new artist and so on.

Here’s how this would look in a basic set-up:

  • GET artists.php – returns the full list of artists
  • GET artists.php?id=1 – returns details only for a specific artist
  • POST artists.php(with some POST elements of course) – creates a new artist entry
  • POST artists.php?id=1(with some POST elements of course) – updates or even deletes a specific artist

And how it would turn in a RESTful approach:

  • GET /artists/ – returns the full list of artists
  • GET /artists/1 – returns details only for a specific artist
  • HEAD /artists/1 – checks if an artist exists
  • POST /artist/ (with some POST elements of course) – creates a new artist entry
  • POST /artists/1(with some POST elements of course) – update s a specific artist
  • DELETE /artists/1 – deletes a specific artist

Bootstrapping

When it comes to bootstrapping a webservice, 4 things must be taken into account:

1) A RESTful route needs to be registered

Needed to instruct the framework to route requests based on the HTTP verb/method. For example when you call GET /artists/, the ArtistsController.php will be loaded and the indexAction will be called.

Below you can see this particular section from the Bootstrap.php file

/**
* Load the REST route
* */
protected function _initRestRoute() {
     // Ensure the front controller is initialized
    $this->bootstrap('FrontController');
    $front = $this->getResource('FrontController');
    // disable views
    $front->setParam('noViewRenderer', true);
    // rgister a RESTful route
    $rest_route = new Zend_Rest_Route($front);
    $front->getRouter()->addRoute('rest', $rest_route);
}

2) The Views system needs to be disabed

Being a web service which sends XML/JSON/text responses back to user, there is no need to load the view, but a custom response object needs to be defined – see below.

The views are disabled in the above piece of code.

3) Loading the authentication plugin

Usually the APIs perform the authentication and/or authorization based on HTTP headers but without relying on (session) cookies. You would not want to use session cookies because, usually, APIs do need to scale and when do scale, they are usually behind a load balancer and you need to take into account the load balancer capabilities to deal with session stickiness – which means to forward the same client to the same machine.

Find below the relevant piece of code that loads the authentication:

/**
 * Load the auth plugin
 * */
protected function _initAuth() {
    Zend_Controller_Front::getInstance()->registerPlugin(
    new ZFWebservice_Controller_Plugin_Auth());
}

4) Sending the response back to client

As mentioned before, there is no need to use the view system, but instead you may define a custom response object that can handle the response headers and body for you. The response object is loaded like this:

/**
 * Load the custom response object
 * */
protected function _initCustomResponse() {
    $front = $this->getResource('FrontController');
    $front->setResponse(new ZFWebservice_Controller_Response_Custom());
}

Authentication and response

Setting-up the authentication mechanism

The authentication takes place with every hit on the API and it is performed in the controller authentication plugin.

In our API, the authentication mechanism relies on a very simple principle: the API user has one API USER and one API KEY, the API USER is sent with every request so the service understand who does the requests. Then, again, with every request an AUTH header is sent which is just hash, computed from request query string , request date and uses the API USER as salt. It is important for the auth hash to contain the date timestamp so you can enforce request expiration rules on the API to prevent the request to intercepted and impersonated.

Preparing the response

In the response class we simply instruct the framework what HTTP status code, headers and body to send back to client, with only a few lines of code.  This happens in ZFWebservice_Controller_Response_Custom class.

$front = Zend_Controller_Front::getInstance();

/**
 * @var Zend_Controller_Request_Abstract
 * */
$request = $front->getRequest();
$response_type = $request->getHeader('X-ZFWS-Accept');
$this->setHttpResponseCode($_status_code);

// factory the response object
$service_response = ZFWebservice_Response_Factory::get($response_type, $_root_element);

$this->setHeader('Content-Type', $service_response->getContentType(), true);
$this->setBody($service_response->get($_response_data));
$this->sendResponse();

Closing up

A full working sample of the webservice can be downloaded here.

The following versions of software were used to run the demo:

  • PHP 5.2.13
  • Zend Framework 1.10.8
  • Apache 2.2.15

Leave a Reply

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