views:

240

answers:

2

Hi, I'm trying to implement a REST API to my website.

My problem is that the default Zend routing gets in the way. I've first tried using Zend_Rest_Route but I haven't been able to understand how I was supposed to use it correctly for "deep" routes, aka website/api/resource1/filter/resource2/id.

Using the default Zend routing, I'd need to create a gigantic Resource1Controller to take care of all the possible actions, and I don't think it's the "good" way to do this.

I've tried using Resauce ( http://github.com/mikekelly/Resauce/), creating an api module and adding routes, but I'm not able to get it working correctly :

The patterns I added were :

    $this->addResauceRoutes(array(
        'api/resource' => 'resource',
        'api/resource/:id' => 'custom',
        'api/resource/filter' => 'resource-filter',
        'api/resource/filter/:id' => 'custom',
    ));

Which then leads to this :

public function addResauceRoutes($routes) {
    $router = Zend_Controller_Front::getInstance()->getRouter();
    foreach ($routes as $pattern => $controller) {
        $router->addRoute($controller,
            new Zend_Controller_Router_Route($pattern, array(
                'module' => 'api',
                'controller' => $controller
                )
            )
        );
    }
    Zend_Controller_Front::getInstance()->setRouter($router);
  • website/api/resource gets me the Resource1Controller, ok
  • website/api/resource/filter gets me to the resource1filterController, ok
  • website/api/resource/filter/:id gets me to a custom controller, ok
  • I'd like for website/api/resource/:id to get me to the same custom controller... But it redirects me to the Resource1Controller.

What solution is there for me to correctly create my API ? Is there a good way to do this with Zend_Rest_Route ?


Edit : Mike,

I felt that it was not appropriate for me to use different controllers since I need the pathes "website/api/resource/:id" and "website/api/resource/filter/:id" to give me almost the exact same result (the only difference is that because the filter is there, I may get a message telling "content filtered" here).

I thought it was a waste creating another almost identical controller when I could've used the same controller and just checked if a parameter "filter" was present.

However, I don't want to use the basic Zend routing since for the path "website/api/resource/filter/resource2" I'd like to have a totally different comportment, so I'd like to use another controller, especially since I'm trying to use Zend_Rest_Action and need my controllers to use the basic actions getAction(), putAction(), postAction() and deleteAction().

A: 

Okay, the reason I didn't get the good controllers was because Resauce uses the controller name as the name of the route, which has to be unique - so second url pointing to "custom" controller couldn't work. Now I'm able to get the files I want :)

So instead of what was previously noted, I use directly the $router->addRoute(); and define new names each times, even if pointing to the same controller.

Example :

$router->addRoute('resource', new Zend_Controller_Router_Route('/api/resources/:id', array('module' => 'api', 'controller' => 'resource')));
$router->addRoute('resourceFiltered', new Zend_Controller_Router_Route('/api/resources/filter1/:id', array('module' => 'api', 'controller' => 'resource', 'filter' => 'filter1'));
Hugo
+1  A: 

Hi Hugo - Please could you explain why it is you need two URI patterns pointing to the same controller. A better solution might be to use a separate controller for each of the two patterns and move any shared logic into your model.

Forcing a unique controller for each routing pattern was an intentional design decision, so I'd be interested to hear more detail about your use case where you feel this isn't appropriate.


I thought it was a waste creating another almost identical controller when I could've used the same controller and just checked if a parameter "filter" was present.

Personally, I think it is cleaner to move the shared logic into the model and to keep your controllers skinny. To me it's not wasteful, it's just more organised - it will make your code easier to manage over time.

If you really need to use the same controller you could always use a query parameter instead, that would work fine:

api/resource/foo?filter=true

That URI would be taken care of by the first route ('api/resource/:id' => 'custom') for free.

But please consider using two controllers, I think that is a better approach.

Mike
Thank you Mike. I already used filter parameters, but some of my controllers had gotten quite fat and using separate controllers will spare me from using a really big switch statement. After thinking a lot about it, I think I'll try using, like you suggested, multiple controllers after all, since I think you have a point when you talk about an easier code to manage over time. Thanks a lot for the useful advice, I guess I wanted to try duplicating code the less possible, but may have ended up making it pretty hard to understand if I had continued that way.
Hugo