Rest Api Routes Not Working

Hello everyone,

I’m trying to implement a relatively simple API. Using the wiki: http://www.yiiframework.com/wiki/175/how-to-create-a-rest-api

I have an ApiController like so:




class ApiController extends Controller

{

    public function filters(){

        return array('accessControl');

    }


    //TODO: REMOVE AFTER TESTING.

    public function accessRules(){

        return array(

            array(

                'allow',

                'users'=>array('*')

            )

        );

    }


    /**

     * GET

     */

    public function actionList()

    {

        echo "list";

    }


    /**

     * GET

     */

    public function actionView()

    {

        echo "view";

    }


    /**

     * POST

     */

    public function actionCreate()

    {

        echo "create";

    }


    /**

     * PUT

     */

    public function actionUpdate()

    {

        echo "update";

    }


    /**

     * DELETE

     */

    public function actionDelete()

    {

        echo "delete";

    }


    /**

     * HEAD

     */

    public function actionMetadata()

    {

        echo "delete";

    }

}



As you can see, it’s just a skeleton, but it should serve my purpose. I’m trying to get the routes working, but for whatever reason, they do not. This is my .htaccess:




RewriteEngine on

# prevent httpd from serving dotfiles (.htaccess, .svn, .git, etc.)

RedirectMatch 403 /\..*$

# if a directory or a file exists, use it directly

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php

RewriteRule . index.php

And this is my configuration in main.php:


'urlManager'=>array(

		'urlFormat'=>'path',

		'rules'=>array(

			'<controller:\w+>/<id:\d+>'=>'<controller>/view',

			'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',

			'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',

                	//REST API routes

	                array('api/list', 'pattern'=>'api/<model:\w+>', 'verb'=>'GET'),

        	        array('api/view', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'GET'),

	                array('api/update', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'PUT'),

	                array('api/delete', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'DELETE'),

	                array('api/create', 'pattern'=>'api/<model:\w+>', 'verb'=>'POST'),

	                array('api/metadata', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'HEAD')

			),

			'showScriptName'=>false

Not really sure what I’m doing wrong. Doesn’t help that I don’t really know much about RegEx.

The controller itself works, but not with those routes. For example, I can go into /api/list or /api/create with no problem, but /api/<myModel> doesn’t work, and it just gives me a 404, unable to find action <myModel>. I’m not sure if the problem is the RegEx (which should not be the case, given that it’s just a w+), or just the array being wrong itself. But it doesn’t seem like that’s the case either, at least not from what I can gather from http://www.yiiframework.com/doc/guide/1.1/en/topics.url#user-friendly-urls

Suggestions?

All right, it seems I just took advantage of my stupidity to make sure it didn’t work. Apparently the API routes just need to be placed BEFORE the controller/action patterns.

It’s even mentioned in the Wiki, but I guess I didn’t look at it because it was just a single line:




'urlManager'=>array(

    'urlFormat'=>'path',

    'rules'=>array(

        'post/<id:\d+>/<title:.*?>'=>'post/view',

        'posts/<tag:.*?>'=>'post/index',

        // REST patterns

        [b]//THE REST PATTERNS MUST BE HERE[/b]

        array('api/list', 'pattern'=>'api/<model:\w+>', 'verb'=>'GET'),

        array('api/view', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'GET'),

        array('api/update', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'PUT'),

        array('api/delete', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'DELETE'),

        array('api/create', 'pattern'=>'api/<model:\w+>', 'verb'=>'POST'),

        [b]//BEFORE OTHER CONTROLLERS[/b]

        // Other controllers

        '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', [b]//THIS WOULD KILL THE CONFIGURATION BECAUSE IT WOULD BE READ FIRST[/b]

    ),

),



As you can see in the code in my first post, I had it the other way around. Basically, since the controller/action RegEx was read first, the app thought (rightfully so) that I was indeed referencing an action called X in my API controller. Inverting the order makes the API controller be found first in the URL manager, effectively taking the api/<model> route.