The Zend Framework 1.9 release added a new feature - Zend_Rest_Controller. Zend_Rest_Controller and Zend_Rest_Route classes go hand in hand. In the previous versions of the Zend Framework, we have had the Zend_Rest_Server component. We still have. Since Zend_Rest_Server provides an RPC like component violating the REST architectural constraint, it is likely to be deprecated in the future versions of the Zend Framework.
In this article let us explore how to make use of Zend_Rest_Route and Zend_Rest_Controller to build a RESTful server application. Zend_Rest_Route routes the request to the appropriate module, controller and action depending on the HTTP request method and URI.
Let's start coding. We build the RESTful application based on the QuickStart project.
You can choose to enable Zend_Rest_Route for the entire application or for specific set of modules. In this example we enable the rest route for the entire application.
Bootstrap the front controller resource and add the rest route.
<?php
protected function _initRestRoute()
{
$this->bootstrap('frontController');
$frontController = Zend_Controller_Front::getInstance();
$restRoute = new Zend_Rest_Route($frontController);
$frontController->getRouter()->addRoute('default', $restRoute);
}
?>Create the file application/controllers/ArticleController.php. We extend Zend_Rest_Controller instead of Zend_Controller_Action. In our controller we are going to have five actions.
These actions are defined as abstract methods in the Zend_Rest_Controller class.
The skeletal controller looks like:
<?php
class ArticleController extends Zend_Rest_Controller
{
public function init()
{
$this->_helper->viewRenderer->setNoRender(true);
}
public function indexAction()
{
}
public function getAction()
{
}
public function postAction()
{
}
public function putAction()
{
}
public function deleteAction()
{
}
}
?>To test the routing of the requests, let's append sample messages to the response object in each action.
<?php
public function indexAction()
{
$this->getResponse()
->appendBody("From indexAction() returning all articles");
}
public function getAction()
{
$this->getResponse()
->appendBody("From getAction() returning the requested article");
}
public function postAction()
{
$this->getResponse()
->appendBody("From postAction() creating the requested article");
}
public function putAction()
{
$this->getResponse()
->appendBody("From putAction() updating the requested article");
}
public function deleteAction()
{
$this->getResponse()
->appendBody("From deleteAction() deleting the requested article");
}
?>On my computer I have installed this application for the domain zfrest.example.com. We use the curl command to test our RESTful server.
Testing the indexAction() : The URI http://zfrest.example.com/article represents the article resource. All articles are returned for this request.
$ curl http://zfrest.example.com/article
I get the following output:
From indexAction() returning all articles
Testing the getAction() : The URI http://zfrest.example.com/article/1 represents the resource - article 1.
$ curl http://zfrest.example.com/article/1
I get the following output:
From getAction() returning the requested article
Testing the postAction() : we make an HTTP POST request to http://zfrest.example.com.
$ curl -d "article=myarticle" http://zfrest.example.com/article/
I get the following output:
From postAction() creating the requested article
Testing the putAction() : we request the article 1 to be updated by making HTTP PUT request to http://zfrest.example.com/article/1
$ curl -d "article=updatedarticle" -X PUT http://zfrest.example.com/article/1
I get the following output:
From putAction() updating the requested article
Testing the deleteAction() : we send an HTTP DELETE request to http://zfrest.example.com/article/1
curl -X DELETE http://zfrest.example.com/article/1
I get the following output:
From deleteAction() deleting the requested article
Zend Framework allows you to build RESTful server applications using the Zend_Rest_Controller component. The curl command is a very useful tool to test RESTful servers. If you don't have the curl command on your computer, you can write a PHP script and make use of the curl extension provided by PHP. In the upcoming posts of this series, I will discuss managing API keys from your RESTful application, returning appropriate HTTP response codes, reading the body from PUT and DELETE requests and more.
Are you going to a build RESTful server using the Zend_Rest_Controller component? Tell me about your experiences.
Create RESTful Applications Using The Zend Framework - Part II : Using HTTP Response Code
Reference:
Wikipedia article on Representational State Transfer
Zend_Rest_Route - Zend Framework manual page
Don't forget appropriate HTTP response codes
One thing often overlooked when creating RESTful services is returning appropriate HTTP response codes. Your controllers and/or view scripts should set codes such as 201 (created), 204 (no content -- useful for delete responses), etc. Make sure you get familiar with both HTTP response codes and headers, as well as the details of the REST specification, when you start developing REST applications -- they'll make your apps interoperate well with a variety of clients out of the box.
Thanks for the comment and
Thanks for the comment and the insightful tip, Matthew.
Thanks for your post a good
Thanks for your post a good starting point on REST with zf. ZF has evolved quickly still working with version 1.0 in some projects. Any idea how much overhead Zend_Rest_Route brings to the table?
Hi Tom, You're welcome. ZF
Hi Tom,
You're welcome.
ZF has indeed grown a lot and at a fast pace. I haven't done any performance benchmarks on Zend_Rest_Route yet. I imagine it won't be much of a concern. Please share the statistics if you happen to benchmark.
Awesome! Thank you. This post
Awesome! Thank you.
This post gave me a kick start on RESTful API development in ZF.
I'm definitely looking forward to read your upcoming posts of this topic.
Thanks
Thanks for the comment.
I will publish more about ZF and REST in the near future.
Zend_Rest_Controller_DbTable
Might also be interested in http://framework.zend.com/wiki/display/ZFPROP/Zend_Rest_Controller_DbTable
I'd like to get some feedback on the proposal before starting to code it into the framework core.
Re: Zend_Rest_Controller_DbTable
Luke,
First of all, I would like to thank you for contributing Zend_Rest_Route and Zend_Rest_Controller.
I have posted my comments to the Zend_Rest_Controller_DbTable component proposal on the Wiki.
Great article
Thank you for introducing the REST .
Looking forward to see the rest of the articles . Also Thanks to Mathew for pointing out http response code .
What about traditional forms?
And what about traditional forms?
How do I post/update new articles from Zend_Form?
Use POST on article/1
Use the "post" method on URI http://example.com/article/1
Here's a sample form
<form method="post" action="/article/1"> <input type="submit" name="submit"> </form>Here's the sample output after submitting the form
If there's no article by id 1, the server should create it. If the request fails, you get the relevant HTTP response code. More about it in the coming articles :)
Can't wait
Thanks.
Can't wait what's coming next :)
Thanks Excellent
Excellent article, simple like that!, thanks very much!!!!!!
The REST components for ZF are not great
Not loving the ZF REST solution so I wrote a post called 'RESTful PHP Applications Despite Zend Framework':
http://mike.mykanjo.co.uk/2009/11/22/restful-php-applications-despite-ze...
contains link to my alternative solution called 'Resauce':
http://github.com/mikekelly/Resauce
Zend REST
Coolness. This is exactly what I was looking for. Thanks!
PUT Request Vars
Okay this one got me for a while. Having spent a few hours figuring out what was going on, I finally came across this snippet in the Zend Framework docs;
http://framework.zend.com/manual/en/zend.controller.plugins.html#zend.co...
You will need that to handle PUT request params.
More please!
Thank you for this article. It really helped to simplify some things I was confused about. I can't wait for more articles on this topic! Seriously...do you think you could post a more advanced article on creating a restful zend framework application? Or a link to one? It's been a few months since this post and I'm anxious to learn more!
You're welcome, Andrew. I
You're welcome, Andrew.
I haven't been able to post blog entries recently due to hectic schedules. I will post more about RESTful applications in the near future.
Next Topic
Hi,
When are you going to release your next post on managing API keys etc?
I would really like to know as I cannot find anything on the net currently.
Cheers.
Ian
Hello Sudheer, First of all,
Hello Sudheer,
First of all, thanks for the excellent article.
Do you think you can provide the full code of the above example as a zip file?
Subra
I'll put it online in the
I'll put it online in the near future.
Let me know if you have a specific problem with the code.
Thanks Sudheer. Pls do update
Thanks Sudheer. Pls do update this thread once you have posted it online. It will very helpful to novices like myself.
Disable Layout?
Thanks for the article. It helped me a lot.
I noticed I was getting all my layout html returned with the response also, so I disable it in the init() function like this: $this->_helper->layout->disableLayout();
We are only supposed to return response codes anyway right?
Correct me if I'm wrong.
You are supposed to return
You are supposed to return the entity, representation of the resource, along with the response code. The entity could be represented using any format you wish - XML, JSON, HTML, text or whatever.
How about more complex routes?
I am currently struggling with Zend_Rest_* to achieve the following Rest routes:
http://example.org/users/123/items/456
I need a Rest route for the user resource: /users/:id
This can be done just like in your example
But I also need a Rest route for the item resource of a given user
/user/:id/items/:itemid
And I can't figure it out. Do you know how to set up routes for that?
I don't think the current
I don't think the current implementation of Zend_Rest_Route allows you to have that kind of route.
I get 403 forbidden error on windows
Hello Sudheer,
I followed the quickstart tutorials and also ur tutorial here. This is how my http.conf file looks:
DocumentRoot "C:\Documents and Settings\aswats\My Documents\MyProjects" . . . <Directory "C:\Documents and Settings\aswats\My Documents\MyProjects"> # # Possible values for the Options directive are "None", "All", # or any combination of: # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews # # Note that "MultiViews" must be named *explicitly* --- "Options All" # doesn't give it to you. # # The Options directive is both complicated and important. Please see # <a href="http://httpd.apache.org/docs/2.2/mod/core.html#options<br /> " title="http://httpd.apache.org/docs/2.2/mod/core.html#options<br /> ">http://httpd.apache.org/docs/2.2/mod/core.html#options<br /> </a> # for more information. # Options Indexes FollowSymLinks # # AllowOverride controls what directives may be placed in .htaccess files. # It can be "All", "None", or any combination of the keywords: # Options FileInfo AuthConfig Limit # AllowOverride None # # Controls who can get stuff from this server. # Order allow,deny Allow from all </Directory>In my httpd-vhosts.conf file I have added the following:
<VirtualHost *:80> ServerName example.local DocumentRoot /askaway/public SetEnv APPLICATION_ENV "development" <Directory /askaway/public> DirectoryIndex index.php AllowOverride All Order allow,deny Allow from all </Directory> </VirtualHost>I also changed the hosts file to include
127.0.0.1 example.local
I followed your instructions step by step. But when I point my browser to http://example.local/article, i get the following error:
Forbidden
You don't have permission to access /article on this server.
Could please tell me what am I doing wrong here?
Set AllowOverride to All
Set AllowOverride to All
next step is defining having custom router
Hi,
Next step will be building custom rest router (perhaps extending the one that exists in ZF) cause current implementation of REST Router is useless.
It doesn't support any arbitrary urls.
Cheers
Zend_Rest_Route can help you
Zend_Rest_Route can help you get started implementing REST style URIs for one resource. For more flexible URIs you have to chain custom routes. I wish to cover this topic in detail in an upcoming post.
Thanks for the comment.
More actions
So if one would like to implement a search on the articles, that has to be a different controller because it is considered a new resource?
P.S
Great Article, Thank you!
Same controller
Articles search should be done in ArticleController. The search parameters must be sent in the form of HTTP GET parameters. The controller should perform the search and return a collection of articles in the response.
for beginners
instruction to help newbe (as me :) )
generate zend application:
zf or zf.bat is in the bin directory od ZendFramework distribution.
change Bootstrap.php as follow:
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
protected function _initRestRoute() {
$this->bootstrap('frontController');
$frontController = Zend_Controller_Front::getInstance();
$restRoute = new Zend_Rest_Route($frontController);
$frontController->getRouter()->addRoute('default', $restRoute);
}
}?>
thx for brilliant introduction!
Step by step please....
Please can anyone mention the step by step procedure for this... i tried the above steps:
First i changed my bootstrap.php file, and added a controller, with some action methods.
When i invoked ..... my application/article/1
i didn't get the expected output, rather i got some error saying:
File not found..
Message: Action "article" does not exist and was not trapped in __call()
Please help....Do i need to create any vieww or models ?
ini settings
If anyone would like to set it in their ini configuration file. Do the following:
UsersConroller
resources.router.routes.rest.type = "Zend_Rest_Route"
resources.router.routes.rest.defaults.controller = object
resources.router.routes.rest.defaults.mod = users
or more than one controller
UsersController and LeadsController
resources.router.routes.rest.type = "Zend_Rest_Route"
resources.router.routes.rest.defaults.controller = object
resources.router.routes.rest.defaults.mod = users, leads
A Marvel on the web my
A Marvel on the web my friend.!! Thanks a ton for such a descriptive guide on zend rest application development. God bless you!!
Very simple and easy to jetstart
Nice article, appreciate your help
Looking forward to your post on "Chaining custom routes" for REST URIs
Action error
HI I am new to zend,
when i added
protected function _initRestRoute() {
$this->bootstrap('frontController');
$frontController = Zend_Controller_Front::getInstance();
$restRoute = new Zend_Rest_Route($frontController);
$frontController->getRouter()->addRoute('default', $restRoute);
these lines to my bootstrap file, every action in other controllers are not working , all actions are mapped to getAction. so getting an error like "Action "get" does not exist and was not trapped in __call() " , the rest part is working fine.
it happened because this code
it happened because this code works for the whole module 'default' ... u can easily create new module f.e. 'restmodule' and change this line in bootstrap
$frontController->getRouter()->addRoute('default', $restRoute);
like this
$frontController->getRouter()->addRoute('restmodule', $restRoute);
about module structure of the zf application u can find in the reference guide zend.com
How i can consume this with
How i can consume this with zend framework?
Where to add Zend_Rest_Route
It's not clear to me where to put
protected function _initRestRoute
Could you clarify? I'm really new to Zend Framework, so please be very verbose and explain anything you think may be necessary.
Tom
Error 500
Hello,
I kept getting an Error 500. I followed every step of this tutorial multiple times but ended up with a 500 every time. I checked out the Zend_Rest_Controller class and turns out that there is another abstract function missing in this tutorial. For anyone experiencing the same problem, add
public function headAction(){}
to your controller.
Cheers!
Post new comment