Today’s users expect online products and services to support a variety of browser-based clients including laptops, tablets and the seemingly endless array of mobile devices such as the iPhone. Rather than attempt to build and maintain multiple versions of the Web application in order to accommodate the diverse array of challenges and advantages presented by each device type, developers are increasingly embracing a unified approach which allows them to manage a single server-side code base which communicates with multiple client-specific interfaces by way of a RESTful Web service.
The Zend Framework’s Zend_Rest component offers PHP developers with an incredibly straightforward approach to building RESTful Web services. Working in conjunction with the Zend_Rest_Route component, it’s possible to create an entirely REST-driven application, or create one or multiple controllers which extend an existing application’s capabilities.
Configuring RESTful Routing Support
You’ll use the Zend_Rest_Route component to identify the parts of your application which are RESTful in nature. Depending on the configuration, you can designate the entire application as RESTful, or limit the behavior to one or more specific modules and controllers. To keep matters simple for the purposes of this tutorial, let’s presume we want to create an entirely new application intended to behave solely as a RESTful API. Begin by creating a new Zend Framework application:
$ zf create project ws.example.com
Creating project at /var/www/ws.example.com
Note: This command created a Web project, for more information setting
up your VHOST, please see docs/README
Next, open up your Bootstrap.php
file, located in the project’s application
directory. You can use the Bootstrap to initialize various project resources, including custom routes. Any method defined within this file’s Bootstrap
class which is prefixed with an underscore will execute upon each invocation of the framework. Create a new method called _initRoutes
which contains the following code:
public function _initRoutes()
{
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$restRoute = new Zend_Rest_Route($front);
$router->addRoute('default', $restRoute);
}
Believe it or not, these four lines are enough to automatically REST-enable all controllers subsequently created within the application.
Building a RESTful Controller
With RESTful routing enabled, let’s next create a controller which contains the various REST endpoints. Suppose the project involves exposing a Web service which allows users to manage a TODO list. Logically such a service should provide users with the ability to view the list (GET), create a new list item (POST), modify a list item (PUT), and delete a list item (DELETE). Begin by creating the controller, which I’ll call Api
:
$ zf create controller Api
Creating a controller at
/var/www/ws.example.com/application/controllers/ApiController.php
Creating an index action method in controller Api
Creating a view script for the index action method at
/var/www/ws.example.com/application/views/scripts/api/index.phtml
Creating a controller test file at
/var/www/ws.example.com/tests/application/controllers/ApiControllerTest.php
Updating project profile '/var/www/ws.example.com/.zfproject.xml'
Next, create the various REST endpoints, each of which is defined by an action:
$ zf create action get Api
...
$ zf create action post Api
...
$ zf create action put Api
...
$ zf create action delete Api
The view-included=0
option tells the ZF tool not to create an associated view for the action. Because our Web service will generate and return JSON, there is no need to use an application layout or view. Once done, the Api
controller will look like this:
<?php
class ApiController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
// action body
}
public function getAction()
{
// action body
}
public function postAction()
{
// action body
}
public function putAction()
{
// action body
}
public function deleteAction()
{
// action body
}
}
With the route and controller in place, the Zend Framework will automatically begin routing the client to the appropriate action based on one of the following URL patterns:
GET /api/
: The API controller’s index action.GET /api/:id
: The API controller’s get action.POST /api/
: The API controller’s post action.PUT /api/:id
: The API controller’s put action.DELETE /api/:id
: The API controller’s delete action.
Because we’re only interested in returning JSON, modify the init()
method to disable the view renderer. Additionally, to keep matters simple, we’ll simulate the management of a TODO list using an array:
public function init()
{
$this->_helper->viewRenderer->setNoRender(true);
$this->_todo = array (
"1" => "Buy milk",
"2" => "Pour glass of milk",
"3" => "Eat cookies"
);
}
Next, modify the index
action to return the entire TODO list:
public function indexAction()
{
echo Zend_Json::encode($this->_todo);
}
Navigate to the /api/
endpoint and you’ll be presented the array in JSON format:
{"1":"Buy milk","2":"Pour glass of milk","3":"Eat cookies"}
Navigate to /api/2
and the get
action will execute, presenting you with:
"Pour glass of milk"
Adding a TODO Item
Both of the above examples demonstrated the magic of REST by highlighting how the underlying action will be chosen based on the URL method (GET in both cases) and pattern. You can add a new TODO list item merely by POSTing data to the /api/
endpoint. Again for reasons of simplicity I’ll simulate adding an item to the TODO list using the array:
public function postAction()
{
$item = $this->_request->getPost('item');
$this->_todo[count($this->_todo) + 1] = $item;
echo Zend_Json::encode($this->_todo);
}
Incidentally, rather than bother with creating a form at this early stage in development you can instead easily execute a POST request using the curl
command-line utility:
$ curl --data "item=Sleep" ws.zend.com/api/
Executing this POST request will result in the following array being returned:
{"1":"Buy milk","2":"Pour glass of milk","3":"Eat cookies","4":"Sleep"}
Where to From Here?
Updating and deleting values from the TODO list really isn’t any different from the examples provided thus far; just be sure to supply the appropriate method and endpoint within your request. Try integrating this functionality into the sample controller!