Yii 1.1: restfullyii

Adds RESTFul API to your Yii application
72 followers

Starship / RestfullYii

Makes quickly adding a RESTFul API to your Yii project easy. RestfullYii provides full HTTP verb support (GET, PUT, POST, DELETE) for your resources, as well as the ability to offset, limit, sort, filter, etc… . You will also have the ability to read and manipulate related data with ease.

RestfullYii has been lovingly rebuilt from the metal and is now 100% test covered! The new event based architecture allows for clean and unlimited customization.

How it works

RestfullYii adds a new set of RESTFul routes to your standard routes, but prepends '/api' .

So if you apply RestfullYii to the 'WorkController' you will get the following new routes by default.

[GET] http://yoursite.com/api/work (returns all works)
[GET] http://yoursite.com/api/work/1 (returns work with PK=1)
[POST] http://yoursite.com/api/work (create new work)
[PUT] http://yoursite.com/api/work/1 (update work with PK=1)
[DELETE] http://yoursite.com/api/work/1 (delete work with PK=1)

Requirements

  • PHP 5.4.0 (or later)*
  • YiiFramework 1.1.14 (or later)
  • PHPUnit 3.7 (or later) to run tests.

    For older versions of PHP (< 5.4) checkout v1.15

Additional Documentation Can be found Here: Git Repo

Installation

  1. Download and place the 'starship' directory in your Yii extension directory.

  2. In config/main.php you will need to add the RestfullYii alias. This allows for flexability in where you place the extension.

'aliases' => array(
        .. .
        'RestfullYii' =>realpath(__DIR__ . '/../extensions/starship/RestfullYii'),
        .. .
    ),

`3. Include ext.starship.RestfullYii.config.routes in your main config (see below) or copy the routes and paste them in your components->urlManager->rules in same config.

'components'=>array(
        'urlManager'=>array(
            'urlFormat'=>'path',
            'rules'=>require(
                dirname(__FILE__).'/../extensions/starship/restfullyii/config/routes.php'
            ),
        ),
)

Controller Setup

Adding a set of RESTFul actions to a controller.

  1. Add the ERestFilter to your controllers filter method.
public function filters()
{
        return array(
            'accessControl', // perform access control for CRUD operations
            array(
                'ext.starship.RestfullYii.filters.ERestFilter + 
                REST.GET, REST.PUT, REST.POST, REST.DELETE'
            ),
        );
}
  1. Add the ERestActionProvider to your controllers actions method.
public function actions()
{
        return array(
            'REST.'=>'ext.starship.RestfullYii.actions.ERestActionProvider',
        );
}
  1. If you are using the accessControl filter you need to make sure that access is allowed on all RESTFul routes.
public function accessRules()
{
        return array(
            array('allow', 'actions'=>array('REST.GET', 'REST.PUT', 'REST.POST', 'REST.DELETE'),
            'users'=>array('*'),
            ),
            array('deny',  // deny all users
                'users'=>array('*'),
            ),
        );
}

Making Requests

To understand how to make RestfullYii API requests its best to look at a few examples. Code examples will be shown first in JavaScript* as an AJAX user* and then using CURL.

* JS examples use jQuery

* Default validation for an AJAX user is !Yii::app()->user->isGuest so the user must be logged in for this type of request.

GET Requests

Getting a list or resources (WorkController)

JavaScript:

$.ajax({
    url:'/api/work',
    type:"GET",
    success:function(data) {
      console.log(data);
    },
    error:function (xhr, ajaxOptions, thrownError){
      console.log(xhr.responseText);
    } 
  });

CURL:

[shell]
curl -i -H "Accept: application/json" -H "X_REST_USERNAME: admin@restuser" -H "X_REST_PASSWORD: admin@Access"\ 
http://my-site.com/api/work

Response:

{
    "success":true,
    "message":"Record(s) Found",
    "data":{
        "totalCount":"30",
        "work":[
            {
                "id": "1",
                "title": "title1",
                "author_id": "1",
                "content": "content1",
                "create_time": "2013-08-07 10:09:41"
            },
            {
                "id": "2",
                "title": "title2",
                "author_id": "2",
                "content": "content2",
                "create_time": "2013-08-08 11:01:11"
            },
            . . .,
        ]
    }
}

Getting a single resource (WorkController)

JavaScript:

$.ajax({
    url:'/api/work/1',
    type:"GET",
    success:function(data) {
      console.log(data);
    },
    error:function (xhr, ajaxOptions, thrownError){
      console.log(xhr.responseText);
    } 
  });

CURL:

[shell]
curl -i -H "Accept: application/json" -H "X_REST_USERNAME: admin@restuser" -H "X_REST_PASSWORD: admin@Access"\
http://my-site.com/api/work/1

Response:

{
    "success":true,
    "message":"Record Found",
    "data":{
        "totalCount":"1",
        "work":[
            {
                "id": "1",
                "title": "title1",
                "author_id": "1",
                "content": "content1",
                "create_time": "2013-08-07 10:09:41"
            }
        ]
    }
}

GET Request: Limit & Offset (WorkController)

You can limit and paginate through your results by adding the limit and offset variables to the request query string.

JavaScript:

$.ajax({
    url:'/api/work?limit=10&offset=30',
    type:"GET",
    success:function(data) {
      console.log(data);
    },
    error:function (xhr, ajaxOptions, thrownError){
      console.log(xhr.responseText);
    } 
  });

CURL:

[shell]
curl -i -H "Accept: application/json" -H "X_REST_USERNAME: admin@restuser" -H "X_REST_PASSWORD: admin@Access"\
http://my-site.com/api/work?limit=10&offset=30

Response:

{
    "success":true,
    "message":"Record(s) Found",
    "data":{
        "totalCount":"30",
        "work":[
            {
                "id": "11",
                "title": "title11",
                "author_id": "11",
                "content": "content11",
                "create_time": "2013-08-11 11:10:09"
            },
            {
                "id": "12",
                "title": "title12",
                "author_id": "12",
                "content": "content12",
                "create_time": "2013-08-08 12:11:10"
            },
            . . .,
        ]
    }
}

GET Request: Sorting results (WorkController)

You can sort your results by any valid param or multiple params as well as provide a sort direction (ASC or DESC). sort=[{"property":"title", "direction":"DESC"}, {"property":"create_time", "direction":"ASC"}]

JavaScript:

$.ajax({
    url:'/api/work?sort=[{"property":"title", "direction":"DESC"}, {"property":"create_time", "direction":"ASC"}]',
    type:"GET",
    success:function(data) {
      console.log(data);
    },
    error:function (xhr, ajaxOptions, thrownError){
      console.log(xhr.responseText);
    } 
  });

CURL:

[shell]
curl -i -H "Accept: application/json" -H "X_REST_USERNAME: admin@restuser" -H "X_REST_PASSWORD: admin@Access"\
http://my-site.com/api/work?sort=%5B%7B%22property%22%3A%22title%22%2C+%22direction%22%3A%22DESC%22%7D%2C+%7B%22property%22%3A%22create_time%22%2C+%22direction%22%3A%22ASC%22%7D%5D

Response:

{
    "success":true,
    "message":"Record(s) Found",
    "data":{
        "totalCount":"30",
        "work":[
            {
                "id": "29",
                "title": "title30b",
                "author_id": "29",
                "content": "content30b",
                "create_time": "2013-08-07 14:05:01"
            },
            {
                "id": "30",
                "title": "title30",
                "author_id": "30",
                "content": "content30",
                "create_time": "2013-08-08 09:10:09"
            },
            {
                "id": "28",
                "title": "title28",
                "author_id": "28",
                "content": "content28",
                "create_time": "2013-08-09 14:05:01"
            },
            . . .,
        ]
    }
}

GET Request: Filtering results (WorkController)

You can filter your results by any valid param or multiple params as well as an operator.

Available filter operators: * in * not in * = * != * > * >= * < * <= * No operator is "LIKE"

/api/post/?filter = [
  {"property": "id", "value" : 50, "operator": ">="}
, {"property": "user_id", "value" : [1, 5, 10, 14], "operator": "in"}
, {"property": "state", "value" : ["save", "deleted"], "operator": "not in"}
, {"property": "date", "value" : "2013-01-01", "operator": ">="}
, {"property": "date", "value" : "2013-01-31", "operator": "<="}
, {"property": "type", "value" : 2, "operator": "!="}
]

POST Requests (Creating new resources)

With POST requests we must include the resource data as a JSON object in the request body.

JavaScript:

var postData = {
    "title": "title31",
    "author_id": "31",
    "content": "content31",
    "create_time": "2013-08-20 09:23:14"
};
 
 $.ajax({
    url:'/api/work',
    data:JSON.stringify(postData)
    type:"POST",
    success:function(data) {
        console.log(data);
    },
    error:function (xhr, ajaxOptions, thrownError){
        console.log(xhr.responseText);
    } 
});

CURL:

[shell]
curl -l -H "Accept: application/json" -H "X_REST_USERNAME: admin@restuser" -H "X_REST_PASSWORD: admin@Access"\
-X POST -d '{"title": "title31", "author_id": "31", "content": "content31", "create_time": "2013-08-20 09:23:14"}' http://my-site.com/api/work

Response:

{
    "success":true,
    "message":"Record Created",
    "data":{
        "totalCount":"1",
        "work":[
            {
                "id": "31",
                "title": "title31",
                "author_id": "31",
                "content": "content31",
                "create_time": "2013-08-20 09:23:14"
            }
        ]
    }
}

PUT Requests (Updating existing resources)

With PUT requests like POST requests we must include the resource data as a JSON object in the request body.

JavaScript:

var postData = {
    "id": "31",
    "title": "title31",
    "author_id": "31",
    "content": "content31",
    "create_time": "2013-08-20 09:23:14"
};
 
 $.ajax({
    url:'/api/work/31',
    data:JSON.stringify(postData)
    type:"PUT",
    success:function(data) {
        console.log(data);
    },
    error:function (xhr, ajaxOptions, thrownError){
        console.log(xhr.responseText);
    } 
});

CURL:

[shell]
curl -l -H "Accept: application/json" -H "X_REST_USERNAME: admin@restuser" -H "X_REST_PASSWORD: admin@Access"\
-X PUT -d '{"id": "31", "title": "title31", "author_id": "31", "content": "content31", "create_time": "2013-08-20 09:23:14"}' http://my-site.com/api/work/31

Response:

{
    "success":true,
    "message":"Record Updated",
    "data":{
        "totalCount":"1",
        "work":[
            {
                "id": "31",
                "title": "title31",
                "author_id": "31",
                "content": "content31",
                "create_time": "2013-08-20 09:23:14"
            }
        ]
    }
}

DELETE Requests (Delete a resource)

JavaScript:

$.ajax({
    url:'/api/work/1',
    type:"DELETE",
    success:function(data) {
      console.log(data);
    },
    error:function (xhr, ajaxOptions, thrownError){
      console.log(xhr.responseText);
    } 
  });

CURL:

[shell]
curl -l -H "Accept: application/json" -H "X_REST_USERNAME: admin@restuser" -H "X_REST_PASSWORD: admin@Access"\
"X-HTTP-Method-Override: DELETE" -X DELETE http://my-site.com/api/work/1

Response:

{
    "success":true,
    "message":"Record Deleted",
    "data":{
        "totalCount":"1",
        "work":[
            {
                "id": "1",
                "title": "title1",
                "author_id": "1",
                "content": "content1",
                "create_time": "2013-08-07 10:09:41"
            }
        ]
    }
}

Sub-Resources

When working with 'many to many' relations you now have the ability to treat them as sub-resources.

Consider:

URL Format: http://mysite.com/api/<controller>/<id>/<many_many_relation>/<many_many_relation_id>

Getting player 3 who is on team 1  
or simply checking whether player 3 is on that team (200 vs. 404)  
GET /api/team/1/players/3  

getting player 3 who is also on team 3  
GET /api/team/3/players/3  

Adding player 3 also to team 2  
PUT /api/team/2/players/3  

Getting all teams of player 3  
GET /api/player/3/teams  

Remove player 3 from team 1 (Injury)
DELETE /api/team/1/players/3  

Team 1 found a replacement, who is not registered in league yet  
POST /api/player  

From payload you get back the id, now place it officially to team 1  
PUT /api/team/1/players/44  

Customization & Configuration

RestfullYii's default behaviors can be easily customized though the built-in event system. Almost all aspects of RestFullYii's request / response handling trigger events. Changing RestfullYii's behaviors is as simple as registering the appropriate event handlers. Event handlers can be registered both globally (in the main config) and locally (at the controller level).

To understand how to do this, lets create a scenario that requires some customization and see how we might accomplish it.

Lets say we have two controllers in our API, WorkController and CategoryController. We would like our API to function in the following ways:

  1. The API should be accessible to JavaScript via AJAX.
  2. The API should not be accessible to any external client.
  3. Only registered users should be allowed to view Work and Category resources.
  4. Only users with the permission REST-UPDATE should be allowed to update works.
  5. Only users with the permission REST-CREATE should be allowed to create works.
  6. Only users with the permission REST-DELETE should be allowed to delete works.
  7. Create, update and delete on categories should be disallowed for all API users.

Now that we know how we would like our API to function, lets take a look at the list above and determine which features can be implemented globally. Since 1, 2 and 3 effect both of our controllers, we can effect these globally by registering a few callbacks in our config/main.php.

To accomplish 1 & 3 we don't have to do anything as this is RestfullYii's default behavior, so that leaves 2. By default RestfullYii does allow access to external clients which is not what we want. Lets change it!

In the /protected/config/main.php params section we will add the following:

$config = array(
    ..,
    'params'=>[
        'RestfullYii' => [
            'req.auth.user'=>function($application_id, $username, $password) {
                return false;
            },
        ]
    ]
);

This tells RestfullYii that when the event 'req.auth.user' is handled it should always return false. Returning false will deny access (true grants it). Similarly validating an AJAX user has it's own event 'req.auth.ajax.user' which (as mentioned earlier) allows access to registered users by default.

That takes care of our global config and we can now focus on features 4-7 while taking care not to break feature 3. Since features 4-6 involve the work controller and user permissions, we can accomplish all of those at the same time. Remember RestfullYii's default behavior is to allow all registered users complete API access and again this is not what we want. Lets change it!

We will now register an event handler locally in the WorkController; To do this we will need to add a special public method in the WorkController called 'restEvents'. Then once we have the 'restEvents' method we can use one other special method 'onRest' to register our event handler. We can call 'onRest' using '$this->onRest()'. 'onRest' takes two params the first is the event name and the second is a Callable that will actually handle the event. This Callable is bound to the controller so the $this context inside the Callable always refers to the current controller. This is true for event handlers registered both globally as well as locally.

Now we are ready modify the output of event handler 'req.auth.ajax.user', but this time instead of overriding the default behavior, we will use the post-filter feature to add our additional user validation. The event name of a post-filter event is always the main event name prefixed with 'post.filter.', thus in our case the event name is 'post.filter.req.auth.ajax.user'. The param(s) passed into a post-filter handler are always the value(s) returned from the main event. Take a look:

class WorkController extends Controller
{
    .. .
 
    public function restEvents()
    {
        $this->onRest('post.filter.req.auth.ajax.user', function($validation) {
            if(!$validation) {
                return false;
            }
            switch ($this->getAction()->getId()) {
                case 'REST.POST':
                    return Yii::app()->user->checkAccess('REST-CREATE');
                    break;
                case 'REST.POST':
                    return Yii::app()->user->checkAccess('REST-UPDATE');
                    break;
                case 'REST.DELETE':
                    return Yii::app()->user->checkAccess('REST-DELETE');
                    break;
                default:
                    return false;
                    break;
            }
        });
    }
 
    .. .
}

Cool! That just leaves feature 7, disallowing create, update, delete on category. Again we will add this change locally, but this time to the CategoryController. Take a look:

class CategoryController extends Controller
{
    .. .
 
    public function restEvents()
    {
        $this->onRest('post.filter.req.auth.ajax.user', function($validation) {
            if(!$validation) {
                return false;
            }
            return ($this->getAction()->getId() == 'REST.GET');
        });
    }
 
    .. .
}

We now have all features implemented!

Defining Custom Routes

Custom routes are very simple to define as all you really need to do is create an event handler for your route and http verb combination (event name = 'req.\.\<route_name>.render'). Lets take a look at some examples.

Here is the list of routes we would like to add to our api:

  1. [GET] /api/category/active

  2. [GET] /api/work/special/\

  3. [PUT] /api/work/special/\/\

  4. [POST] /api/work/special/\

  5. [DELETE] /api/work/special/\/\

Custom Route 1

As you tell from the route the request will be handled by the Category controller. So that is where we will add our event handler.

class CategoryController extends Controller
{
    .. .
    public function restEvents()
    {
        $this->onRest('req.get.active.render', function() {
            //Custom logic for this route.
            //Should output results.
            $this->emitRest('req.render.json', [
                [
                    'type'=>'raw',
                    'data'=>['active'=>true]
                ]
            ])
        });
    }
}

Custom Routes 2-5

These routes all involve the Work controller. So that is where we will add our event handlers.

class WorkController extends Controller
{
    .. .
 
    public function restEvents()
    {
        $this->onRest('req.get.special.render', function($param1) {
            echo CJSON::encode(['param1'=>$param1]);
        });
 
        $this->onRest('req.put.special.render', function($data, $param1, $param2) {
            //$data is the data sent in the PUT
            echo CJSON::encode(['data'=>$data, $param1, $param2]);
        });
 
        $this->onRest('req.post.special.render', function($data, $param1) {
            //$data is the data sent in the POST
            echo CJSON::encode(['data'=>$data, 'param1'=>$param1, 'param2'=>$param2]);
        });
 
        $this->onRest('req.delete.special.render', function($param1, $param2) {
            echo CJSON::encode(['param1'=>$param1, 'param2'=>$param2]);
        });
    }

Testing

Running the project's automated tests.

Unit Tests

  1. Make sure you that you have the correct database and database user in the test config (/WEB_ROOT/protected/extensions/starship/RestfullYii/tests/testConfig.php).
  2. % cd /WEB_ROOT/protected/extensions/starship/RestfullYii/tests
  3. % phpunit unit/

Contributors

Resources

License

Starship / RestfullYii is released under the WTFPL license - http://sam.zoy.org/wtfpl/. This means that you can literally do whatever you want with this extension.

Total 20 comments

#16911 report it
tavangar79 at 2014/04/13 01:55am
The system is unable to find the requested action "rest.get".

hi i get this error The system is unable to find the requested action "rest.get".

i use php 5.5 yii 1.1.14

my urlManager was 'urlManager' => array( 'urlFormat' => 'path', 'showScriptName' => false, 'caseSensitive' => false, 'rules' => require( dirname(FILE).'/../extensions/starship/RestfullYii/config/routes.php' ), ),

i change it to

'urlManager' => array( 'urlFormat' => 'path', 'showScriptName' => false, 'rules' => require( dirname(FILE).'/../extensions/starship/RestfullYii/config/routes.php' ), ),

and its work maybe it help you

#16886 report it
Fire at 2014/04/08 03:29pm
ERestResourceHelper.php:148 $data is null when I PUT data

Hi there,

When I try to update, an error is being generated it says that Invalid argument supplied for foreach() (starship/RestfullYii/components/ERestResourceHelper.php:148)

On closer inspections, it seams that $data is null in the setAttributes function.

Can you shed some light no why my put data is not being transfered into the $data variable?

#16885 report it
Amador Cuenca at 2014/04/08 03:18pm
Example

Hi guys,

I don't understand how to implement this. Could someone provide me an example?

Thanks,

#16797 report it
Fire at 2014/03/29 03:40am
not saving data

Hi there, I have implemented RestfullYii, and got it working. However, when I do a post, it returns a success, even with a new ID, but when i look in the database, the record is not created.

What could be the problem?

#16769 report it
Fire at 2014/03/26 06:43am
where is this "WorkController"?

It would be useful to see the WorkController... I am confused as how PUT,GET,DELETE works. Ie: how does this extension know which model to perform these actions on?

#16578 report it
Daantje at 2014/03/07 05:28am
@evan108108

I've tried your solution, with a little correction, but it's throwing exceptions. It just doesn't want to go deeper into my relations... Maybe that's a good thing ;)

This is the error I'm getting:

{"success":false,"message":"Property \"VideoInvites.video.cuepoints\" is not defined.","data":{"errorCode":500,"message":"Property \"VideoInvites.video.cuepoints\" is not defined."}}

This is my restEvents method:

public function restEvents()
    {
        $this->onRest('config.dev.flag', function() {
            return true;
        });
 
        $this->onRest('model.instance', function() {
            return new VideoInvites('mine');
        });
 
        $this->onRest('model.find.all', function($model) {
            $data = $model::model()->mine()->with(array('video:mine','video.cuepoints','video.cuepoints.question'))->findAll();
            foreach($data as $k=>$m){
                if($m->video == null){
                    unset($data[$k]);
                }
            }
            return $data;
        });
 
        $this->onRest('post.filter.model.with.relations', function($relations){
           if($this->getAction()->getId() == 'REST.GET') {
              return ['video','video.cuepoints','video.cuepoints.question'];
           }
           return $relations;
        });
 
        $this->onRest('req.get.resources.render', function($data, $model_name, $relations, $count, $visibleProperties=[], $hiddenProperties=[]) {
            $this->setHttpStatus(((count($data) > 0)? 200: 204));
            $this->renderJSON([
                'type'              => 'rest',
                'success'           => (($count > 0)? true: false),
                'message'           => (($count > 0)? "Record(s) Found": "No Record(s) Found"),
                'totalCount'        => $count,
                'modelName'         => $model_name,
                'relations'         => $relations,
                'visibleProperties' => $visibleProperties,
                'hiddenProperties'  => $hiddenProperties,
                'data'              => $data,
            ]);
        });
    }

EDIT

This is working for me for now. I've used this solution. And changed my event methot to this:

public function restEvents()
    {
        $this->onRest('model.instance', function() {
            return new VideoInvites('mine');
        });
 
        $this->onRest('model.find.all', function($model) {
            $data = $model::model()->mine()->with(array('video:mine','video.cuepoints','video.cuepoints.question'))->findAll();
            foreach($data as $k=>$m){
                if($m->video == null){
                    unset($data[$k]);
                }
            }
            return $data;
        });
 
        $this->onRest('req.get.resources.render', function($data, $model_name, $relations, $count, $visibleProperties=[], $hiddenProperties=[]) {
            $this->setHttpStatus(((count($data) > 0)? 200: 204));
            header('Content-type: application/json');
 
            echo CJSON::encode(['success'=>true, 'message'=>'Record(s) Found', 'data'=>[
                'totalCount'=>count($data),
                $model_name=>$data
            ]]);
        });
    }

That is working for me. Maybe this is a solution for the extension to?

--Daantje

#16553 report it
evan108108 at 2014/03/05 09:56am
@Daantje

Yes you are correct. Nested relationships are currently only one level deep. However you can simply catch the render event and do what you would like.

//Code not tested...
 
$this->onRest('post.filter.model.with.relations', function($relations){
   if($this->controller->action->id == 'REST.GET') {
      return ['video.mine','video.cuepoints','video.cuepoints.question'];
   }
   return $relations;
});
 
$this->onRest('req.get.resource.render', function($data, $model_name, $relations, $count, $visibleProperties=[], $hiddenProperties=[]) {
  //RENDER CODE HERE!
});
#16549 report it
Daantje at 2014/03/05 08:34am
Nested relations not parsed in json result?

Hi,

I have something strange. When I have nested relations, it's only parsing the direct relation, not the nested ones?

This is what I have:

$this->onRest('model.find.all', function($model) {
    return $model::model()->mine()->with(array('video:mine','video.cuepoints','video.cuepoints.question'))->findAll();
});

But I only get video model, not video->cuepoints and video->cuepoints->question:

{
    "success":true,
    "message":"Record(s) Found",
    "data":{
        "totalCount":"4",
        "videoInvites":[
            {
                "id":"3",
                "video_id":"7",
                "email":"",
                "user_id":"2",
                "video":{
                    "id":"7",
                    "user_id":"1",
                    "name":"How to make a paper plane"
                }
            }
        ]
    }
}

When I var_dump the $model it has all relations in the dataset, so what am I missing? I'm using version 1.24.

#16475 report it
Matthew Torres at 2014/02/26 10:41pm
Using your extension the right way

Hi Evan,

I find your extension very useful, but I am very concerned on the right way to use your extension. Basically, I am using your extension by extending it in my controller so my controller would look like this:

class MyController extends ERestController{
...
   // Default rest post but adding more data
   public function doRestCreate() {
     //my code
   }
 
   // Default rest put but adding more data
   public function doRestUpdate($id, $data) {
     //my code
   }
 
   // My custom rest post action
   public function doCustomRestCreateAction(){
      //my code
   }
}

I was wondering if I am doing the right thing. Hoping to get some of your insights.

#16438 report it
fuguochang at 2014/02/23 04:29am
Other questions

i am so lucky that you can reply my questoins;and i reslove the problem by using you way; but i have other questions:

here i have a uri :xx.xx.com/api/job ,verb is get and the model is job ,the controller is

JonController

1、indeed,the uri above can give us the json data ,but here i want to add some business logic befor return the json data ,where can i add the code ? and which event can i use? because here does not use any resource , it is just a default action .

2、i think job are the resouces , because the default return data are linked to model 'Job';but you provide the event like req.get.resouce.render, it is seems for the config :'api/<controller:\w+>'=>['/REST.GET', 'verb'=>'GET'], we can define many resources,here for the 'Job' Model and event 'req.get.list.render' , is a kind resource for getting the list of Model Job , but for event 'req.get.list1.render' is another kind resource for Model Job , I don not know Whether my understanding is correct 3、how to distinguish the event req.get.resource .render and req.get.resources.render , how can i use the the events , and what request i send , it is can be processed by the above events?

4、i noticed that you can not proccess the 'like' operator ,so if i want to add some parameters by myself ,for the above uri:xx.xx.com/api/job ,if i want to add some parameters, i can get parameters by Yii::app()->request , I don not know Whether my understanding is correct ??

recently i wanto use this extension on my project ,bu i can not understand the usage fully,so if you have example code you can provide me, thanks a lot,my email is changfuguo@qq.com

#16392 report it
evan108108 at 2014/02/18 12:14pm
@fuguochang

Your clue is 'errorCode: 401, message: "Unauthorized"'.

RESTFullYii has several built in authentication mechanisms (See: req.auth.ajax.user, req.auth.ajax.user, req.auth.cors).

I am guessing you are trying to access this via your browser? If so you could either login and try again as req.auth.ajax.user will by default allow logged in users or hook the 'req.auth.ajax.user' auth event in your controller and simply return true to allow all users full access (be very careful!):

$this->onRest('req.auth.ajax.user', function() {
    return true;
});
#16381 report it
fuguochang at 2014/02/17 02:54am
why i get Unauthorized result json ?

{ success: false, message: "Unauthorized", data: { errorCode: 401, message: "Unauthorized" } }

here is my controller ,i just copy form you guid , i do realy not know how to use the new version? please help me

<?php

class WorkController extends Controller{

    public function filters()
    {
            return array(
                'accessControl', // perform access control for CRUD operations
                array(
                    'ext.starship.RestfullYii.filters.ERestFilter + 
                    REST.GET, REST.PUT, REST.POST, REST.DELETE'
                ),
            );
    }

     public function actions(){
        return array(
            'REST.'=>'ext.starship.RestfullYii.actions.ERestActionProvider'
        );

     }

     public function accessRules(){
        return array(
            array(
                'allow','actions'=>array('REST.GET','REST.PUT','REST.POST','REST.DELETE'),'users'=>array('*'),  
            ),  
            array('deny','users'=>array('*')),
        ); 
     }
     public function restEvents()
        {
              $this->onRest('req.get.special.render', function($param1) {
                   echo CJSON::encode(['param1'=>$param1]);
              });
              $this->onRest('req.put.special.render', function($data, $param1, $param2) {
               //$data is the data sent in the PUT
                   echo CJSON::encode(['data'=>$data, $param1, $param2]);
               });

              $this->onRest('req.post.special.render', function($data, $param1) {
              //$data is the data sent in the POST
                   echo CJSON::encode(['data'=>$data, 'param1'=>$param1, 'param2'=>$param2]);
               });

              $this->onRest('req.delete.special.render', function($param1, $param2) {
                   echo CJSON::encode(['param1'=>$param1, 'param2'=>$param2]);
               });
        }


public function actionrestGet(){
    exec('source ~/.bash_profile; errHunter /home/qec/test' ,$result, $ret);
    echo json_encode($result);
}

}

#16347 report it
fuguochang at 2014/02/13 07:04am
can you provide us a whole controller?

i used your's old version , and it is can work well,so i want to use the latest version,but i do not know how to write a controller ,can you provide us a simple example ?

with the new version ,should not we write the action ??

the error , but we can not write a function named "REST.GET" ,?? The system is unable to find the requested action "REST.GET".

#16309 report it
DigitalAlien at 2014/02/08 03:48pm
Controller Example

Can anyone who has implemented this please provide an example controller and how to call the actions? I need to call an API to validate a user and then that user be able to call the api and actions to get data from a database. I am not exactly sure how this is done.

#16065 report it
evan108108 at 2014/01/15 03:26pm
@radoo: Get Routes

Sure its supported, simply modify the routes to your liking.

If you change the urlFormat to 'get' you can always do something like

myController/REST.GET
myController/REST.GET&id=1
myController/REST.GET&id=1&param1=XXX&param2=XXX

myController/REST.POST

myController/REST.PUT&id=1

myController/REST.DELETE&id=1

etc...

#16050 report it
radoo at 2014/01/14 03:58pm
works only with "path" urlFormat ?

This is an excellent extension, and a must have (as backend) when using modern JS frameworks like AngularJS.

However, our team develops with urlFormat = get, and from the looks of it, this extension doesn't support both get and path urlFormat..

How would you go about implementing such a feature properly, so the extension would work with both settings?

#15901 report it
hemc at 2013/12/28 04:18am
How to authenticate

I want to create an api for fetch user data and other information from the system. In request system will get authentication data (id,username and password) with i have in a table. I want to validate this data against db for each request.

Request format is as

{
  "request": {
    "signin": {
      "id": "12345",
      "username": "test",
      "password": "xyz"
    },
    "memberid": "03000000015",
    "remarks": { "remark": "check user request remark" }
  }
}

How i can authenticate user with this extension ?

#15479 report it
evan108108 at 2013/11/13 10:49pm
@stelgenhof Re: Syntax error in routes.php

This syntax is perfectly valid as this extension requires php5.4+ . Seems like you are using an older version of PHP. I recommend that you upgrade to 5.4 or greater.

#15478 report it
stelgenhof at 2013/11/13 09:55pm
Syntax error in routes.php

The included routes.php (config folder), causes PHP syntax errors. This is because there are square brackets in the file and it does not return the routes as an array.

This happens in v1.22 and v1.23.

Anyone else experienced this also?

EDIT: In fact in many files the square brackets seem to cause syntax errors. I am wondering if something is wrong on my side...

Nevermind... Just figured out this is the shorthand array syntax. My system is not upgraded to PHP 5.4 yet...:(

Cheers! Sacha

#15400 report it
lutek at 2013/11/06 01:31pm
HTTP/1.1 401 Unauthorized

Hi,

I got the same problem with curl authorization (windows 7, php 5.4 curl 7.33). I have created new Yii project and installed extensions with instructions but still have error: HTTP/1.1 401 Unauthorized

I have tried debugging app and one variable "$SERVER['HTTP_X'.$application_id.'_USERNAME']" seems to be unset/empty.

I tried te same app on debian with php 5.4 and te same problem, login by site works, by curl doesnt.

I lost idea what can be wrong. Could you help me?

Leave a comment

Please to leave your comment.

Create extension