0

I am building RESTful API in Zend Framework 2. My route is article/person. I know that if id is not passed in url then it will call getList() method, not get().

In my case, I don't pass id as a get or post parameter but I pass it in HTTP header. As I use id to perform database operations, I want it to call get() method, not getList(). How can I tweak the code to do that?

Is it possible to specify exact method name to call in routing?

Geek
  • 8,280
  • 17
  • 73
  • 137

3 Answers3

4

I don't pass id as a get or post parameter but I pass it in HTTP header

This does make your REST invalid, so it isn't actually REST anymore. You therefor cannot use the RestfulAbstractController without customization.

You can either write your own abstract controller or you override the getIdentifier method:

protected function getIdentifier($routeMatch, $request)
{
    $identifier = $this->getIdentifierName();
    $headers    = $request->getHeaders();

    $id = $headers->get($identifier)->getFieldValue();
    if ($id !== false) {
        return $id;
    }

    return false;
}

Make sure you set the correct identifier name in each controller. In this case, the identifier name should match the name of the header you are using.

Note this will be used for GET, PUT, PATCH, DELETE and HEAD requests, not only for GET!

/edit:

The getIdentifier method is called in the flow a controller determines which method to run. Normally, it's this:

  1. The controller is constructed
  2. The controller's dispatch is called (the controller is Dispatchable)
  3. The dispatch triggers an event "dispatch"
  4. The method onDispatch listens to this event
  5. In the AbstractRestfulController the method tries to determine which method to call

For #5, it checks for example if the request is a GET request. If so, it checks if there is an identifier given. If so, the get() is used. If not, the getList() is used. The "if there is an identifier given" check is done with the getIdentifier() method.

If you extend the AbstractRestfulController with your own abstract controller and override the getIdentifier(), you can determine your own identifier. This way, you can check for the header instead of the route parameter or query parameter.

Jurian Sluiman
  • 13,498
  • 3
  • 67
  • 99
  • When this `getIdentifier()` will be called and for what purpose? – Geek Jan 03 '14 at 04:55
  • @Akash I updated the answer with the code flow of the AbstractRestfulController. I linked to various parts in the source so you can check this at Github. – Jurian Sluiman Jan 03 '14 at 08:32
  • I have tried your code but its giving me error ---Call to a member function getFieldValue() on a non-object what is the solution for that? – Bhavik Joshi Mar 17 '15 at 09:39
  • Where to assign value to identifier? – Bhavik Joshi Mar 17 '15 at 09:40
  • The result from `$headers->get($identifier)`returns a Header object or `false` when the header does not exist. You probably fetch a header which isn't available. You might check the existence first with `$headers->has($identifier)` which returns either `true` or `false`. – Jurian Sluiman Apr 03 '15 at 08:14
1

Override AbstractRestfulController to be able to tweak all the functionality related to the id.

class YourController extends AbstractRestfulController {

    //in the constructor, ensure that your id name is set to the header variable you are using
    public function __construct() {
        $this->identifierName = 'id'; // Override $identifierName value specified in AbstractRestfulController, if you need it
    }

    protected function getIdentifier($routeMatch, $request)
    {

        //first of all, check if the id is set in the $routeMatch params, this is, in the normal way
        $id= parent::getIdentifier($routeMatch, $request);     
        if ($id !== false) {
            return $id;
        }

        //if the id its not set, check out the headers 
        $id =  $request->getHeaders()->get($this->getIdentifierName())->getFieldValue();
        if ($id !== false) {
            return $id;
        }

        return false;
    }

}
Carlos Robles
  • 10,828
  • 3
  • 41
  • 60
  • When this getIdentifier() will be called and for what purpose? – Geek Jan 03 '14 at 05:19
  • the system calls getIdentifier() automatically to determine if there is an id in the request. if there is, it callss the get method instead of the getlist. `AbstractRestfulController` has this function defined, and return the id from the routematch. thats why you override this function, so the system will call it instead of the default, and you can return the id you have in headers. – Carlos Robles Jan 03 '14 at 10:16
  • Be aware this answer contains php errors (`super` is no php keyword) and doesn't much more than providing information present in my earlier posted answer. There is no real need for using the parent method to retrieve the identifier first, as you could override the header identifier. If you need it, I would swap them. I am not downvoting as the idea is correct, but mind there are issues with this answer! – Jurian Sluiman Jan 03 '14 at 10:59
  • @JurianSluiman thanks for pointing it, I wrote it by heart and i confused parent with super. Our question are very similar, your explanations are much better, and I think my code is more complete, but the main idea is the same (i suppose because it is the best way). about overriding the function but keeping a call to the parent method, i do it since i think it will be more flexible, i.e. if him decide later to use the normal GET param for the id. anyways, I will +1 on your answer for the 'didactic' style – Carlos Robles Jan 03 '14 at 11:15
  • i said that i'll upvote, but it will be tomorrow since i reached my limit today! – Carlos Robles Jan 03 '14 at 11:22
  • +1 for correct answer. But, `Jurian`'s answer has better description in addition to correct code, so I have selected his as correct. – Geek Jan 03 '14 at 11:46
  • Agree with everything! +1 in the comment, actually useful. – Carlos Robles Jan 03 '14 at 12:25
  • what to do if I get id from header I tried to fetch header info in constructor but i am not able to get it? – Bhavik Joshi Mar 17 '15 at 09:42
0

I think the easiest approach is to call get method from getList method

public function getList(){
   // get id from header
   $id = $this->getRequest()->getHeaders()->get("id-header-field");
   if ($id){
       return $this->get($id);
   }
   else{ /* return list */}
}

public function get($id){
  return JsonModel($data);
}