Monday, November 29, 2010

Create RESTful Applications Using The Zend Framework - Part II : Using HTTP Response Code

In our last example, we used Zend_Rest_Route and Zend_Rest_Controller to demonstrate how to map requests to controller actions. We also used the response object to send text content in the HTTP response. In this article let us send appropriate HTTP response codes using the response object.
RFC 2616 describes HTTP response codes to use in various contexts.
In this example, we will use a few response codes
  • 200 OK - successfully returning the requested articles
  • 201 Created - article has been created
  • 204 No Content - article has been deleted
  • 404 Not Found - no resource found at the requested URI
  • 503 Service Unavailable - the server is experiencing heavy load. Try later.
We will cover other HTTP response codes in upcoming articles on the subject.
Let's start coding. Grab the ArticleContoller.php from the article Create RESTful Applications Using The Zend Framework
.

Demonstrating the usage of HTTP response code 200

Modify the indexAction() of our ArticleController

<?phppublic function indexAction()
    {
         
$this->getResponse()
            ->
setHttpResponseCode(200)
            ->
appendBody("all articles content");
    }
?>
The Zend_Controller_Response_Abstract class has the method setResponseCode() using which we can set the HTTP response code. If we weren't using Zend Framework, we would simply use the PHP function header().
In this article, we again use cUrl from the command line to view the response. The -v switch to the curl command prints the output in verbose mode.
curl http://zfrest.example.com/article -v
* About to connect() to zfrest.example.com port 80 (#0)
*   Trying 127.0.0.1... connected
* Connected to zfrest.example.com (127.0.0.1) port 80 (#0)
> GET /article HTTP/1.1
> User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.0
> Host: zfrest.example.com
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sat, 23 Jan 2010 18:11:08 GMT
< Server: Apache/2.2.13 (Fedora)
< X-Powered-By: PHP/5.2.11
< Content-Length: 20
< Connection: close
< Content-Type: text/html; charset=UTF-8
< 
* Closing connection #0
all articles content
If you observe carefully, the response contains the line

HTTP/1.1 200 OK

Demonstrating the usage of HTTP response code 201

Let's perform HTTP POST action on the article resource. We modify the postAction of ArticleController

<?phppublic function postAction()
    {
        
$this->getResponse()
             ->
setHttpResponseCode(201)
            ->
appendBody("created the article\n")
            ->
appendBody("http://zfrest.example.com/article/5");

    }
?>
In the response body we also mention the URI from which the newly created article can be accessed.
The output looks like

curl -d "article=myarticle" http://zfrest.example.com/article/ -v
* About to connect() to zfrest.example.com port 80 (#0)
*   Trying 127.0.0.1... connected
* Connected to zfrest.example.com (127.0.0.1) port 80 (#0)
> POST /article/ HTTP/1.1
> User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.0
> Host: zfrest.example.com
> Accept: */*
> Content-Length: 17
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 201 Created
< Date: Sat, 23 Jan 2010 17:52:51 GMT
< Server: Apache/2.2.13 (Fedora)
< X-Powered-By: PHP/5.2.11
< Content-Length: 55
< Connection: close
< Content-Type: text/html; charset=UTF-8
< 
created the article
* Closing connection #0
http://zfrest.example.com/article/5

Demonstrating the usage of HTTP response code 204

Let's delete an article. The user agent does not require any content in the body when the article is deleted.
We modify the deleteAction() of ArticleController

<?php
 
public function deleteAction()
    {
        
$this->getResponse()
            ->
setHttpResponseCode(204);

    }
?>
The output on the command line looks like:
curl -X DELETE http://zfrest.example.com/article/12 -v
* About to connect() to zfrest.example.com port 80 (#0)
*   Trying 127.0.0.1... connected
* Connected to zfrest.example.com (127.0.0.1) port 80 (#0)
> DELETE /article/12 HTTP/1.1
> User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.0
> Host: zfrest.example.com
> Accept: */*
> 
< HTTP/1.1 204 No Content
< Date: Sat, 23 Jan 2010 17:58:14 GMT
< Server: Apache/2.2.13 (Fedora)
< X-Powered-By: PHP/5.2.11
< Content-Length: 0
< Connection: close
< Content-Type: text/html; charset=UTF-8
< 
* Closing connection #0

Demonstrating the usage of HTTP response code 404

Let's try to access article 20 which does not exist.
Modify the getAction() of ArticleController. For the sake of example, let's pretend the getAction() is prepared to respond to only non-existent resources.
<?php public function getAction()
    {
        
$this->getResponse()
            ->
setHttpResponseCode(404)
            ->
appendBody("requested article 20 not found");

    }
?>
The output looks like:

curl http://zfrest.example.com/article/20 -v

* About to connect() to zfrest.example.com port 80 (#0)
*   Trying 127.0.0.1... connected
* Connected to zfrest.example.com (127.0.0.1) port 80 (#0)
> GET /article/20 HTTP/1.1
> User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.0
> Host: zfrest.example.com
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Date: Sat, 23 Jan 2010 18:17:56 GMT
< Server: Apache/2.2.13 (Fedora)
< X-Powered-By: PHP/5.2.11
< Content-Length: 30
< Connection: close
< Content-Type: text/html; charset=UTF-8
< 
* Closing connection #0
requested article 20 not found

Demonstrating the usage of HTTP response code 503

Lastly, let's respond with the HTTP code 503.
Modify the putAction of ArticleController

public function putAction()
    {
        $this->getResponse()
            ->setHttpResponseCode(503)
            ->appendBody("unable to process put requests. Please try later");
 
    }
The output looks like:

curl -d "article=updatedarticle" -X PUT http://zfrest.example.com/article/1 -v
* About to connect() to zfrest.example.com port 80 (#0)
*   Trying 127.0.0.1... connected
* Connected to zfrest.example.com (127.0.0.1) port 80 (#0)
> PUT /article/1 HTTP/1.1
> User-Agent: curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.12.4.5 zlib/1.2.3 libidn/1.9 libssh2/1.0
> Host: zfrest.example.com
> Accept: */*
> Content-Length: 22
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 503 Service Temporarily Unavailable
< Date: Sat, 23 Jan 2010 18:21:48 GMT
< Server: Apache/2.2.13 (Fedora)
< X-Powered-By: PHP/5.2.11
< Content-Length: 48
< Connection: close
< Content-Type: text/html; charset=UTF-8
< 
* Closing connection #0
unable to process put requests. Please try later
When implementing a REST client you could simply examine the HTTP response code to check whether the request was successful. One common area where you can see response codes being examined is AJAX applications.
For your convenience, I am posting the entire code of the ArticleController.php below.


<?php
class ArticleController extends Zend_Rest_Controller{

    public function 
init()
    {
        
$this->_helper->viewRenderer->setNoRender(true);
    }

    public function 
indexAction()
    {
         
$this->getResponse()
            ->
setHttpResponseCode(200)
            ->
appendBody("all articles content");
    }

    public function 
getAction()
    {
        
$this->getResponse()
            ->
setHttpResponseCode(404)
            ->
appendBody("requested article 20 not found");

    }

    public function 
postAction()
    {
        
$this->getResponse()
             ->
setHttpResponseCode(201)
            ->
appendBody("created the article\n")
            ->
appendBody("http://zfrest.example.com/article/5");

    }

    public function 
putAction()
    {
        
$this->getResponse()
            ->
setHttpResponseCode(503)
            ->
appendBody("unable to process put requests. Please try later");

    }

    public function 
deleteAction()
    {
        
$this->getResponse()
            ->
setHttpResponseCode(204);

    }

}
?>

No comments:

Post a Comment