Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Step by Step create RESTful Application

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on October 31, 2012

Beside AbstractActionController, ZF2 has AbstractRestfulController that provide RESTful implementation that simply maps HTTP request methods to controller methods : GET maps to either get() or getList(), POST maps to create(), PUT maps to update(), and DELETE maps to delete().


REpresentational State Transfer (REST) is a style of software architecture for distributed systems such as the World Wide Web. REST has emerged as a predominant Web service design model. REST-style architectures consist of clients and servers. Clients initiate requests to servers; servers process requests and return appropriate responses. Requests and responses are built around the transfer of representations of resources. A resource can be essentially any coherent and meaningful concept that may be addressed. A representation of a resource is typically a document that captures the current or intended state of a resource.

I want to show you how to create simple RESTful Application.
1. First step, create your Restful Module like the following :

2. Configure module.config.php

return array(
    'controllers' => array(
        'invokables' => array(
            'SanRestful\Controller\SampleRestful' => 'SanRestful\Controller\SampleRestfulController',
            'SanRestful\Controller\SampleClient' => 'SanRestful\Controller\SampleClientController',
        ),
    ),
    'router' => array(
        'routes' => array(
            'SanRestful' => array(
                'type'    => 'Literal',
                'options' => array(
                    // Change this to something specific to your module
                    'route'    => '/san-restful',
                    'defaults' => array(
                        // Change this value to reflect the namespace in which
                        // the controllers for your module are found
                        '__NAMESPACE__' => 'SanRestful\Controller',
                        'controller'    => 'SampleRestful',
                    ),
                ),
                
                'may_terminate' => true,
                'child_routes' => array(
                    'client' => array(
                        'type'    => 'Segment',
                        'options' => array(
                            'route'    => '/client[/:action]',
                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                            ),
                            'defaults' => array(
                                'controller' => 'SampleClient',
                                'action'     => 'index'
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ),
);

3.Create The SampleRestfulController

namespace SanRestful\Controller;

use Zend\Mvc\Controller\AbstractRestfulController;

class SampleRestfulController extends AbstractRestfulController
{    
    public function get($id)
    {
        $response = $this->getResponseWithHeader()
                         ->setContent( __METHOD__.' get current data with id =  '.$id);
        return $response;
    }
    
    public function getList()
    {
        $response = $this->getResponseWithHeader()
                         ->setContent( __METHOD__.' get the list of data');
        return $response;
    }
    
    public function create($data)
    {
        $response = $this->getResponseWithHeader()
                         ->setContent( __METHOD__.' create new item of data :
                                                    <b>'.$data['name'].'</b>');
        return $response;
    }
    
    public function update($id, $data)
    {
       $response = $this->getResponseWithHeader()
                        ->setContent(__METHOD__.' update current data with id =  '.$id.
                                            ' with data of name is '.$data['name']) ;
       return $response;
    }
    
    public function delete($id)
    {
        $response = $this->getResponseWithHeader()
                        ->setContent(__METHOD__.' delete current data with id =  '.$id) ;
        return $response;
    }
    
    // configure response
    public function getResponseWithHeader()
    {
        $response = $this->getResponse();
        $response->getHeaders()
                 //make can accessed by *   
                 ->addHeaderLine('Access-Control-Allow-Origin','*')
                 //set allow methods
                 ->addHeaderLine('Access-Control-Allow-Methods','POST PUT DELETE GET');
        
        return $response;
    }
}

4. Create the client Controller

namespace SanRestful\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\Http\Client as HttpClient;

class SampleClientController extends AbstractActionController
{
    public function indexAction()
    {   
        $client = new HttpClient();
        $client->setAdapter('Zend\Http\Client\Adapter\Curl');
        
        $method = $this->params()->fromQuery('method', 'get');
        $client->setUri('http://localhost:80'.$this->getRequest()->getBaseUrl().'/san-restful');
        
        switch($method) {
            case 'get' :
                $client->setMethod('GET');
                $client->setParameterGET(array('id'=>1));                
                break;
            case 'get-list' :
                $client->setMethod('GET');
                break;
            case 'create' :
                $client->setMethod('POST');
                $client->setParameterPOST(array('name'=>'samsonasik'));
                break;
            case 'update' :
                $data = array('name'=>'ikhsan');
                $adapter = $client->getAdapter();
                
                $adapter->connect('localhost', 80);
                $uri = $client->getUri().'?id=1';
                // send with PUT Method, with $data parameter
                $adapter->write('PUT', new \Zend\Uri\Uri($uri), 1.1, array(), http_build_query($data)); 
                
                $responsecurl = $adapter->read();
                list($headers, $content) = explode("\r\n\r\n", $responsecurl, 2);
                $response = $this->getResponse();
                 
                $response->getHeaders()->addHeaderLine('content-type', 'text/html; charset=utf-8');
                $response->setContent($content);
                
                return $response;
            case 'delete' :
                $adapter = $client->getAdapter();
                
                $adapter->connect('localhost', 80);
                $uri = $client->getUri().'?id=1'; //send parameter id = 1
                // send with DELETE Method
                $adapter->write('DELETE', new \Zend\Uri\Uri($uri), 1.1, array());
                
                $responsecurl = $adapter->read();
                list($headers, $content) = explode("\r\n\r\n", $responsecurl, 2);
                $response = $this->getResponse();
                 
                $response->getHeaders()->addHeaderLine('content-type', 'text/html; charset=utf-8');
                $response->setContent($content);
                
                return $response;
        }
        
        //if get/get-list/create
        $response = $client->send();
        if (!$response->isSuccess()) {
            // report failure
            $message = $response->getStatusCode() . ': ' . $response->getReasonPhrase();
            
            $response = $this->getResponse();
            $response->setContent($message);
            return $response;
        }
        $body = $response->getBody();
        
        $response = $this->getResponse();
        $response->setContent($body);
        
        return $response;
    }
}

5. Testing :
Call in browser : http://localhost/zf2app/public/san-restful/client?method=update

Btw, I published the sourcecode at my github account : https://github.com/samsonasik/SanRestful

References :
1. http://en.wikipedia.org/wiki/Representational_state_transfer
2. http://stackoverflow.com/questions/10384778/curl-request-with-headers-separate-body-a-from-a-header
3. http://stackoverflow.com/questions/1691530/sending-a-file-via-http-put-in-php
4. http://zf2.readthedocs.org/en/latest/modules/zend.mvc.controllers.html#the-abstractrestfulcontroller

53 Responses

Subscribe to comments with RSS.

  1. Fredrik Wahlqvist (@FredWahlqvist) said, on December 17, 2012 at 4:08 pm

    Hi, another great example,

    Do you now how you can make a authorisation layer on this with something like bjyauthorise?

  2. samsonasik said, on December 17, 2012 at 4:55 pm

    i have not try bjyauthorize yet

  3. Mario said, on March 13, 2013 at 12:25 am

    Hi,

    Thank you for this useful example. I think it would be awesome if you can explain an approach to secure the restful api using basic authentication or digest over https, assuming the client is in other server than the rest api.

    Thank you again!

  4. Mario said, on March 19, 2013 at 5:44 am

    Hi again.
    I’m trying to understand why you are using connect/write/read in update and delete methods and why you just are using send() for the rest of methods. I looked into Zend\Http\Client.php send() method code and I see that there it is used connect/write/read too.

    Could you please help me to understand?

    Thank you!

    • samsonasik said, on March 19, 2013 at 6:06 am

      for PUT and DELETE, Zend doesn’t have setParameterMETHOD. so use adapter to Send request to the remote server with its request method.

  5. Mario said, on March 19, 2013 at 6:20 am

    Thanks a lot for your fast response and for clarifying this.
    Now I understand.

    Great blog!

  6. Thomas Sens said, on April 18, 2013 at 7:53 am

    case ‘update’ :
    $client->setMethod(‘PUT’);
    $client->setParameterGET(array(‘id’=>1));
    $client->setParameterPOST(array(‘name’=>’ikhsan’));
    break;
    case ‘delete’ :
    $client->setMethod(‘DELETE’);
    $client->setParameterGET(array(‘id’=>1));
    break;

  7. Khem said, on May 6, 2013 at 2:25 pm

    Hi Samsonasik,
    I have an Ajax request that contains some params (username, password) to authenticate. The method I use is POST. I use RestfulController to handle params and do some business logic and return json result. With get($id) method only accept one param, how can I get username, and password to do authentication and return?
    Thank you!

    • samsonasik said, on May 8, 2013 at 2:06 am

      if you use POST, you should use create() function that pass $data that can be array.

      • Khem said, on May 8, 2013 at 4:05 pm

        That’s right. Thank you a lot.

  8. xmanalex said, on May 7, 2013 at 4:12 am

    HI, Samsonasik,

    I am not getting where this method is from: $this->getResponseWithHeader() – it does not seem to exist in the response class, am I just missing something obvious?
    Thank you

    • xmanalex said, on May 7, 2013 at 7:22 am

      This what the stuff I was looking for 🙂

      var_dump(
      $this->params()->fromQuery(),
      $this->getRequest()->getQuery(),
      $this->getEvent()->getRouteMatch()->getParams()
      );

  9. Mario said, on May 8, 2013 at 5:07 am

    Hi Abdul,

    A couple of questions:
    How do you think is the better way to make a search using variable fields? How the getList() method from the restful controller will receive the parameters?

    Thanks a lot for any tip!

    Best!

    • samsonasik said, on May 8, 2013 at 5:49 pm

      No, if you want to pass a parameter, use get().

      • Mario said, on May 9, 2013 at 12:36 am

        Ok, but I wonder how can I make a search and return a set of records in a restful webservice like this one?
        Or by example if I want to do some pagination sending the offset and limit values to the webservice in order to get a subset of records with the getList() method, I am confused with this scenario.

        I apologize if this sounds to obvious but I can’t find the way to do it.

        Best regards

  10. Aaron Murray said, on May 23, 2013 at 11:25 am

    Excellent overview! Really helps me with a component I am working on for my app. Curious though:

    in module.config.php you have:

    ‘route’ => ‘/client[/:action]’,
    ‘constraints’ => array(
    ‘controller’ => ‘[a-zA-Z][a-zA-Z0-9_-]*’,
    ),

    Should the constraint be on the action rather than the controller? Or is it actually necessary at all. The code works both ways (with ‘controller’ or ‘action’) so I am a bit confused. Otherwise this is a really great starting point for restful API’s in an app.

    Peace / Aaron

  11. Iftikhar Ahmad said, on July 10, 2013 at 2:27 pm

    This is a good example. I want to make the API with authentication. If you can help me, how to get it done.

  12. ravindar said, on July 31, 2013 at 7:59 pm

    Hello Sam,

    How are you send the $file data using restful api?

  13. zmoukit said, on October 10, 2013 at 11:32 pm

    Thank you for this useful example.

    I tried implement your example in my project but I have this error :

    A 404 error occurred
    Page not found.
    The requested controller was unable to dispatch the request.
    Controller:
    SanRestful\Controller\SampleRestful
    No Exception available

    an idea ??

  14. zmoukit said, on October 17, 2013 at 6:02 pm

    Thank you for your response

    it was a problem with ACL.

    By cons I have another question :

    I want to use a class in models with a method in which I will put the same code of the index action :

    $client->setUri(‘http://localhost:80/Patient-webService’);

    switch($method) {
    case ‘get’ :
    /*$client->setMethod(‘GET’);
    $client->setParameterGET(array(‘id’=>1));*/
    /*exit(‘lopend !!!’);
    break;
    case ‘get-list’ :
    //$client->setMethod(‘GET’);
    exit(‘lopend !!!’);
    break;
    case ‘create’ :
    $client->setMethod(‘POST’);
    $client->setParameterPOST($post);
    break;
    case ‘update’ :

    exit(‘lopend !!!’);
    case ‘delete’ :

    exit(‘lopend !!!’);
    }

    but it doesn’t call to the restful controller

  15. Harshal said, on December 17, 2013 at 6:12 pm

    Hi, I have been following your tutorials for a while, I have a question how can i use DynamoDb as back end in the api?
    Any help would be great.

  16. Kumar said, on June 4, 2014 at 4:58 pm

    very nice example but can i call the url like
    http://localhost/zf2app/public/san-restful/client/method/update
    instead of http://localhost/zf2app/public/san-restful/client?method=update

  17. Vivek said, on August 29, 2014 at 1:25 pm

    can you please tell me where do these two controllers are linked??

    • Vivek said, on August 29, 2014 at 2:40 pm

      Also can you tell me where do i put the database connection model , in Restful Controller or AbstractAction Controller?

  18. arun said, on September 9, 2014 at 12:44 pm

    is it fine to use SampleRestfulController ? for all method

  19. heera said, on September 14, 2014 at 3:08 pm

    I have an issue, I used SampleClientController to find all parameters passed using get method and used these parameters in SampleRestfulController, it’s working fine on local but on main server it show an issue given below:

    Strict Standards: Declaration of RestfulApi\Controller\SampleRestfulController::get() should be compatible with Zend\Mvc\Controller\AbstractRestfulController::get($id) in /var/www/html/gaba/module/RestfulApi/src/RestfulApi/Controller/SampleRestfulController.php on line 18

    It come because, here I am trying to get all parameters values not only id.But I need to send more params so how it will be solve????

    • samsonasik said, on September 15, 2014 at 12:44 am

      more then one parameters should be handle by create($data) method, use POST instead.

      • heera said, on September 16, 2014 at 12:27 pm

        But how I will access the post data in SampleClientController ? Using $method = $this->params()->fromQuery(‘method’); I get method but not able to find all post data.

        Please reply for this problem, how post data will access in SampleRestfulController create method ?
        I tried $this->getRequest()->isPost() method but not getting posted data.

      • heera said, on September 16, 2014 at 12:51 pm

        Hi,Please ignore previous reply for post data problem.
        I used post method and get posted data.In SampleClientController I used
        $request = $this->getRequest();
        $data = (array) $request->getPost();

        and get all data and after use $client->setParameterPOST($data); to set data and access data from SampleRestfulController create method.

        Is this right???? or other better process ?

      • samsonasik said, on September 16, 2014 at 2:33 pm

        there is $request->getPost()->toArray() for that 😉

      • heera said, on September 18, 2014 at 1:12 pm

        thanks…

      • arun said, on September 19, 2014 at 12:38 pm

        Hi samsonasik,

        I need to create more than one api (e.g login, session_update, user_create etc ) using post method ,
        then how it should be implement , currently i use $request->getPost()->toArray() method to get the request data in which I pass other params i.e api => ‘apiname’ and in SampleRestfulController I use switch case on apiname and process that functionality.

        Is this right method or should create other controller for each api ?

      • samsonasik said, on September 19, 2014 at 1:29 pm

        you can make other controller(s) for separate usage to make it easier to manage, managing to much logic in one file should be avoided.

  20. Algie said, on October 22, 2014 at 11:20 am

    Hi Samsonik,

    This is a great blog. But, can you make a blog using PhlyRestfully module from Zend Framework 2? That would be more awesome if you have time.

    Thanks

  21. banibal said, on January 2, 2015 at 6:20 pm

    Thank you for this example, it helps understanding. But when I tried it with a simple get (public/san-restful/client), it took some time on each request (1.5 to 2.5 seconds). 99% of spent time is in the SampleClientController on this line : $response = $client->send();
    Could there be a faster version ?

    • samsonasik said, on January 2, 2015 at 7:28 pm

      it uses curl, so i think it depends on your server configuration 😉

      • banibal said, on January 2, 2015 at 11:29 pm

        Thanks, I don’t exactly understand why this worked, but I changed the port I listen to in my httpd.conf (8080 instead of 80) and adjusted the ServerName and it’s faster now 🙂

  22. babak faghihian said, on November 9, 2015 at 9:21 pm

    hi abdul the question is :if you want to get the most ten popular clients what should you do adding a new controller ?

  23. suma said, on June 8, 2022 at 6:54 pm

    Am getting error like,
    Error in cURL request: SSL certificate problem: self signed certificate.

    please can u suggest what should i do for the above issue.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: