|
|
|
@ -147,54 +147,16 @@ While not required, it is recommended that you develop your RESTful APIs as an a
|
|
|
|
|
your Web front end and back end. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Adding or Removing Endpoints |
|
|
|
|
---------------------------- |
|
|
|
|
Creating Resource Classes |
|
|
|
|
------------------------- |
|
|
|
|
|
|
|
|
|
As explained above, controllers and actions are used to implement API endpoints. |
|
|
|
|
RESTful APIs are all about accessing and manipulating resources. In Yii, a resource can be an object of any class. |
|
|
|
|
However, if your resource classes extend from [[yii\base\Model]] or its child classes (e.g. [[yii\db\ActiveRecord]]), |
|
|
|
|
you may enjoy the following benefits: |
|
|
|
|
|
|
|
|
|
To add an API endpoint servicing a new kind of model (resource), create a new controller class by extending |
|
|
|
|
[[yii\rest\ActiveController]] or [[yii\rest\Controller]]. The difference between these two base controller |
|
|
|
|
classes is that the former is a subclass of the latter and implements a commonly needed actions to deal |
|
|
|
|
with ActiveRecord. The controller class should be named after the model class with the `Controller` suffix. |
|
|
|
|
For example, for the `Post` model, you would create a `PostController` class. |
|
|
|
|
|
|
|
|
|
If your new controller class extends from [[yii\rest\ActiveController]], you already have a whole set of |
|
|
|
|
endpoints available out of box, as shown in the quick example. You may want to disable some of the actions |
|
|
|
|
or customize them. This can be easily done by overriding the `actions()` method, like the following, |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
public function actions() |
|
|
|
|
{ |
|
|
|
|
$actions = parent::actions(); |
|
|
|
|
|
|
|
|
|
// disable the "delete" and "create" actions |
|
|
|
|
unset($actions['delete'], $actions['create']); |
|
|
|
|
|
|
|
|
|
// customize the data provider preparation with the "prepareDataProvider()" method |
|
|
|
|
$actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider']; |
|
|
|
|
|
|
|
|
|
return $actions; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public function prepareDataProvider() |
|
|
|
|
{ |
|
|
|
|
// prepare and return a data provider for the "index" action |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
You can certainly create new actions like you do with regular controllers. The only difference is that |
|
|
|
|
instead of calling [[yii\base\Controller::render()]] to render views, you directly return the data |
|
|
|
|
in your action. For example, |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
public function actionSearch($keyword) |
|
|
|
|
{ |
|
|
|
|
$result = SolrService::search($keyword); |
|
|
|
|
return $result; |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
The data will be automatically formatted and sent to the client, as we will explain in the next section. |
|
|
|
|
* Input data validation; |
|
|
|
|
* Query, create, update and delete data, if extending from [[yii\db\ActiveRecord]]; |
|
|
|
|
* Customizable data formatting (to be explained in the next section). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Formatting Response Data |
|
|
|
@ -203,7 +165,7 @@ Formatting Response Data
|
|
|
|
|
By default, Yii supports two response formats for RESTful APIs: JSON and XML. If you want to support |
|
|
|
|
other formats, you should configure [[yii\rest\Controller::supportedFormats]] and also [[yii\web\Response::formatters]]. |
|
|
|
|
|
|
|
|
|
The data formatting is in general a two-step process: |
|
|
|
|
Formatting response data in general involves two steps: |
|
|
|
|
|
|
|
|
|
1. The objects (including embedded objects) in the response data are converted into arrays by [[yii\rest\Serializer]]; |
|
|
|
|
2. The array data are converted into different formats (e.g. JSON, XML) by [[yii\web\ResponseFormatterInterface|response formatters]]. |
|
|
|
@ -213,32 +175,46 @@ Step 1 involves some major development effort as explained below.
|
|
|
|
|
|
|
|
|
|
When the [[yii\rest\Serializer|serializer]] converts an object into an array, it will call the `toArray()` method |
|
|
|
|
of the object if it implements [[yii\base\ArrayableInterface]]. If an object does not implement this interface, |
|
|
|
|
an array consisting of all its public properties will be returned. |
|
|
|
|
its public properties will be returned instead. |
|
|
|
|
|
|
|
|
|
For classes extending from [[yii\base\Model]] or [[yii\db\ActiveRecord]], besides directly overriding `toArray()`, |
|
|
|
|
you may also override the `fields()` method and/or the `extraFields()` method to customize the data to be returned. |
|
|
|
|
you may also override the `fields()` method and/or the `extraFields()` method to customize the data being returned. |
|
|
|
|
|
|
|
|
|
The method [[yii\base\Model::fields()]] declares a set of fields of an object that should be included in the result. |
|
|
|
|
The default implementation returns all attributes of a model as the output fields. You can customize it to add, |
|
|
|
|
remove, rename or reformat the fields. For example, |
|
|
|
|
The method [[yii\base\Model::fields()]] declares a set of *fields* that should be included in the result. |
|
|
|
|
A field is simply a named data item. In a result array, the array keys are the field names, and the array values |
|
|
|
|
are the corresponding field values. The default implementation of [[yii\base\Model::fields()]] is to return |
|
|
|
|
all attributes of a model as the output fields; for [[yii\db\ActiveRecord::fields()]], by default it will return |
|
|
|
|
the names of the attributes whose values have been populated into the object. |
|
|
|
|
|
|
|
|
|
You can override the `fields()` method to add, remove, rename or redefine fields. For example, |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
class User extends \yii\db\ActiveRecord |
|
|
|
|
// explicitly list every field, best used when you want to make sure the changes |
|
|
|
|
// in your DB table or model attributes do not cause your field changes (to keep API backward compatibility). |
|
|
|
|
public function fields() |
|
|
|
|
{ |
|
|
|
|
public function fields() |
|
|
|
|
{ |
|
|
|
|
$fields = parent::fields(); |
|
|
|
|
return [ |
|
|
|
|
// field name is the same as the attribute name |
|
|
|
|
'id', |
|
|
|
|
// field name is "email", the corresponding attribute name is "email_address" |
|
|
|
|
'email' => 'email_address', |
|
|
|
|
// field name is "name", its value is defined by a PHP callback |
|
|
|
|
'name' => function () { |
|
|
|
|
return $this->first_name . ' ' . $this->last_name; |
|
|
|
|
}, |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// remove fields that contain sensitive information |
|
|
|
|
unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']); |
|
|
|
|
// filter out some fields, best used when you want to inherit the parent implementation |
|
|
|
|
// and blacklist some sensitive fields. |
|
|
|
|
public function fields() |
|
|
|
|
{ |
|
|
|
|
$fields = parent::fields(); |
|
|
|
|
|
|
|
|
|
// add a new field "full_name" defined as the concatenation of "first_name" and "last_name" |
|
|
|
|
$fields['full_name'] = function () { |
|
|
|
|
return $this->first_name . ' ' . $this->last_name; |
|
|
|
|
}; |
|
|
|
|
// remove fields that contain sensitive information |
|
|
|
|
unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']); |
|
|
|
|
|
|
|
|
|
return $fields; |
|
|
|
|
} |
|
|
|
|
return $fields; |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
@ -274,30 +250,335 @@ For example, `http://localhost/users?fields=id,email&expand=profile` may return
|
|
|
|
|
] |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
You may wonder who triggers the conversion from objects to arrays when an action returns an object or object collection. |
|
|
|
|
The answer is that this is done by [[yii\rest\Controller::serializer]] in the [[yii\base\Controller::afterAction()|afterAction()]] |
|
|
|
|
method. By default, [[yii\rest\Serializer]] is used as the serializer that can recognize resource objects extending from |
|
|
|
|
[[yii\base\Model]] and collection objects implementing [[yii\data\DataProviderInterface]]. The serializer |
|
|
|
|
will call the `toArray()` method of these objects and pass the `fields` and `expand` user parameters to the method. |
|
|
|
|
If there are any embedded objects, they will also be converted into arrays recursively. |
|
|
|
|
|
|
|
|
|
If all your resource objects are of [[yii\base\Model]] or its child classes, such as [[yii\db\ActiveRecord]], |
|
|
|
|
and you only use [[yii\data\DataProviderInterface]] as resource collections, the default data formatting |
|
|
|
|
implementation should work very well. However, if you want to introduce some new resource classes that do not |
|
|
|
|
extend from [[yii\base\Model]], or if you want to use some new collection classes, you will need to |
|
|
|
|
customize the serializer class and configure [[yii\rest\Controller::serializer]] to use it. |
|
|
|
|
You new resource classes may use the trait [[yii\base\ArrayableTrait]] to support selective field output |
|
|
|
|
as explained above. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### HATEOAS Support |
|
|
|
|
|
|
|
|
|
TBD |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating Controllers and Actions |
|
|
|
|
-------------------------------- |
|
|
|
|
|
|
|
|
|
So you have the resource data and you have specified how the resource data should be formatted, the next thing |
|
|
|
|
to do is to create controller actions to expose the resource data to end users. |
|
|
|
|
|
|
|
|
|
Yii provides two base controller classes to simplify your work of creating RESTful actions: |
|
|
|
|
[[yii\rest\Controller]] and [[yii\rest\ActiveController]]. The difference between these two controllers |
|
|
|
|
is that the latter provides a default set of actions that are specified designed to deal with |
|
|
|
|
resources represented as ActiveRecord. So if you are using ActiveRecord and you are comfortable with |
|
|
|
|
the provided built-in actions, you may consider creating your controller class by extending from |
|
|
|
|
the latter. Otherwise, extending from [[yii\rest\Controller]] will allow you to develop actions |
|
|
|
|
from scratch. |
|
|
|
|
|
|
|
|
|
Both [[yii\rest\Controller]] and [[yii\rest\ActiveController]] provide the following features which will |
|
|
|
|
be described in detail in the next few sections: |
|
|
|
|
|
|
|
|
|
* Response format negotiation; |
|
|
|
|
* API version negotiation; |
|
|
|
|
* HTTP method validation; |
|
|
|
|
* User authentication; |
|
|
|
|
* Rate limiting. |
|
|
|
|
|
|
|
|
|
[[yii\rest\ActiveController]] in addition provides the following features specifically for working |
|
|
|
|
with ActiveRecord: |
|
|
|
|
|
|
|
|
|
* A set of commonly used actions: `index`, `view`, `create`, `update`, `delete`, `options`; |
|
|
|
|
* User authorization in regard to the requested action and resource. |
|
|
|
|
|
|
|
|
|
When creating a new controller class, a convention in naming the controller class is to use |
|
|
|
|
the type name of the resource and use singular form. For example, to serve user information, |
|
|
|
|
the controller may be named as `UserController`. |
|
|
|
|
|
|
|
|
|
Creating a new action is similar to creating an action for a Web application. The only difference |
|
|
|
|
is that instead of rendering the result using a view by calling the `render()` method, for RESTful actions |
|
|
|
|
you directly return the data. The [[yii\rest\Controller::serializer|serializer]] and the |
|
|
|
|
[[yii\web\Response|response object]] will handle the conversion from the original data to the requested |
|
|
|
|
format. For example, |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
public function actionSearch($keyword) |
|
|
|
|
{ |
|
|
|
|
$result = SolrService::search($keyword); |
|
|
|
|
return $result; |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
If your controller class extends from [[yii\rest\ActiveController]], you should set |
|
|
|
|
its [[yii\rest\ActiveController::modelClass||modelClass]] property to be the name of the resource class |
|
|
|
|
that you plan to serve through this controller. The class must implement [[yii\db\ActiveRecordInterface]]. |
|
|
|
|
|
|
|
|
|
With [[yii\rest\ActiveController]], you may want to disable some of the built-in actions or customize them. |
|
|
|
|
To do so, override the `actions()` method like the following: |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
public function actions() |
|
|
|
|
{ |
|
|
|
|
$actions = parent::actions(); |
|
|
|
|
|
|
|
|
|
// disable the "delete" and "create" actions |
|
|
|
|
unset($actions['delete'], $actions['create']); |
|
|
|
|
|
|
|
|
|
// customize the data provider preparation with the "prepareDataProvider()" method |
|
|
|
|
$actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider']; |
|
|
|
|
|
|
|
|
|
return $actions; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public function prepareDataProvider() |
|
|
|
|
{ |
|
|
|
|
// prepare and return a data provider for the "index" action |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
The following list summarizes the built-in actions supported by [[yii\rest\ActiveController]]: |
|
|
|
|
|
|
|
|
|
* [[yii\rest\IndexAction|index]]: list resources page by page; |
|
|
|
|
* [[yii\rest\ViewAction|view]]: return the details of a specified resource; |
|
|
|
|
* [[yii\rest\CreateAction|create]]: create a new resource; |
|
|
|
|
* [[yii\rest\UpdateAction|update]]: update an existing resource; |
|
|
|
|
* [[yii\rest\DeleteAction|delete]]: delete the specified resource; |
|
|
|
|
* [[yii\rest\OptionsAction|options]]: return the supported HTTP methods. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Routing |
|
|
|
|
------- |
|
|
|
|
|
|
|
|
|
With resource and controller classes ready, you can access the resources using the URL like |
|
|
|
|
`http://localhost/index.php?r=user/create`. As you can see, the format of the URL is the same as that |
|
|
|
|
for Web applications. |
|
|
|
|
|
|
|
|
|
In practice, you usually want to enable pretty URLs and take advantage of HTTP verbs. |
|
|
|
|
For example, a request `POST /users` would mean accessing the `user/create` action. |
|
|
|
|
This can be done easily by configuring the `urlManager` application component in the application |
|
|
|
|
configuration like the following: |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
'urlManager' => [ |
|
|
|
|
'enablePrettyUrl' => true, |
|
|
|
|
'enableStrictParsing' => true, |
|
|
|
|
'showScriptName' => false, |
|
|
|
|
'rules' => [ |
|
|
|
|
['class' => 'yii\rest\UrlRule', 'controller' => 'user'], |
|
|
|
|
], |
|
|
|
|
] |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
Compared to the URL management for Web applications, the main new thing above is the use of |
|
|
|
|
[[yii\rest\UrlRule]] for routing RESTful API requests. This special URL rule class will |
|
|
|
|
create a whole set of child URL rules to support routing and URL creation for the specified controller(s). |
|
|
|
|
For example, the above code is roughly equivalent to the following rules: |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
[ |
|
|
|
|
'PUT,PATCH users/<id>' => 'user/update', |
|
|
|
|
'DELETE users/<id>' => 'user/delete', |
|
|
|
|
'GET,HEAD users/<id>' => 'user/view', |
|
|
|
|
'POST users' => 'user/create', |
|
|
|
|
'GET,HEAD users' => 'user/index', |
|
|
|
|
'users/<id>' => 'user/options', |
|
|
|
|
'users' => 'user/options', |
|
|
|
|
] |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
And the following API endpoints are supported by this rule: |
|
|
|
|
|
|
|
|
|
* `GET /users`: list all users page by page; |
|
|
|
|
* `HEAD /users`: show the overview information of user listing; |
|
|
|
|
* `POST /users`: create a new user; |
|
|
|
|
* `GET /users/123`: return the details of the user 123; |
|
|
|
|
* `HEAD /users/123`: show the overview information of user 123; |
|
|
|
|
* `PATCH /users/123` and `PUT /users/123`: update the user 123; |
|
|
|
|
* `DELETE /users/123`: delete the user 123; |
|
|
|
|
* `OPTIONS /users`: show the supported verbs regarding endpoint `/users`; |
|
|
|
|
* `OPTIONS /users/123`: show the supported verbs regarding endpoint `/users/123`. |
|
|
|
|
|
|
|
|
|
You may configure the `only` and `except` options to explicitly list which actions to support or which |
|
|
|
|
actions should be disabled, respectively. For example, |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
[ |
|
|
|
|
'class' => 'yii\rest\UrlRule', |
|
|
|
|
'controller' => 'user', |
|
|
|
|
'except' => ['delete', 'create', 'update'], |
|
|
|
|
], |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
You may also configure `patterns` or `extra` to redefine existing patterns or add new patterns supported by this rule. |
|
|
|
|
For example, to support a new action `search` by the endpoint `GET /users/search`, configure the `extra` option as follows, |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
[ |
|
|
|
|
'class' => 'yii\rest\UrlRule', |
|
|
|
|
'controller' => 'user', |
|
|
|
|
'extra' => [ |
|
|
|
|
'GET search' => 'search', |
|
|
|
|
], |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
You may have noticed that the controller ID `user` appears in plural form as `users` in the endpoints. |
|
|
|
|
This is because [[yii\rest\UrlRule]] automatically pluralizes controller IDs for them to use in endpoints. |
|
|
|
|
You may disable this behavior by setting [[yii\rest\UrlRule::pluralize]] to be false, or if you want |
|
|
|
|
to use some special names you may configure the [[yii\rest\UrlRule::controller]] property. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Authentication |
|
|
|
|
-------------- |
|
|
|
|
|
|
|
|
|
Unlike Web applications, RESTful APIs should be stateless, which means sessions or cookies should not |
|
|
|
|
be used. Therefore, each request should come with some sort of authentication credentials because |
|
|
|
|
the user authentication status may not be maintained by sessions or cookies. A common practice is |
|
|
|
|
to send a secret access token with each request to authenticate the user. Since an access token |
|
|
|
|
can be used to uniquely identify and authenticate a user, **the API requests should always be sent |
|
|
|
|
via HTTPS to prevent from man-in-the-middle (MitM) attacks**. |
|
|
|
|
|
|
|
|
|
There are different ways to send an access token: |
|
|
|
|
|
|
|
|
|
* [HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication): the access token |
|
|
|
|
is sent as the username. This is should only be used when an access token can be safely stored |
|
|
|
|
on the API consumer side. For example, the API consumer is a program running on a server. |
|
|
|
|
* Query parameter: the access token is sent as a query parameter in the API URL, e.g., |
|
|
|
|
`https://example.com/users?access-token=xxxxxxxx`. Because most Web servers will keep query |
|
|
|
|
parameters in server logs, this approach should be mainly used to serve `JSONP` requests which |
|
|
|
|
cannot use HTTP headers to send access tokens. |
|
|
|
|
* [OAuth 2](http://oauth.net/2/): the access token is obtained by the consumer from an authorization |
|
|
|
|
server and sent to the API server via [HTTP Bearer Tokens](http://tools.ietf.org/html/rfc6750), |
|
|
|
|
according to the OAuth2 protocol. |
|
|
|
|
|
|
|
|
|
Yii supports all of the above authentication methods and can be further extended to support other methods. |
|
|
|
|
|
|
|
|
|
To enable authentication for your APIs, do the following two steps: |
|
|
|
|
|
|
|
|
|
1. Configure [[yii\rest\Controller::authMethods]] with the authentication methods you plan to use. |
|
|
|
|
2. Implement [[yii\web\IdentityInterface::findIdentityByAccessToken()]] in your [[yii\web\User::identityClass|user identity class]]. |
|
|
|
|
|
|
|
|
|
For example, to enable all three authentication methods explained above, you would configure `authMethods` |
|
|
|
|
as follows, |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
class UserController extends ActiveController |
|
|
|
|
{ |
|
|
|
|
public $authMethods = [ |
|
|
|
|
'yii\rest\HttpBasicAuth', |
|
|
|
|
'yii\rest\QueryParamAuth', |
|
|
|
|
'yii\rest\HttpBearerAuth', |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
Each element in `authMethods` should be an auth class name or a configuration array. An auth class |
|
|
|
|
must implement [[yii\rest\AuthInterface]]. |
|
|
|
|
|
|
|
|
|
Implementation of `findIdentityByAccessToken()` is application specific. For example, in simple scenarios |
|
|
|
|
when each user can only have one access token, you may store the access token in an `access_token` column |
|
|
|
|
in the user table. The method can then be readily implemented in the `User` class as follows, |
|
|
|
|
|
|
|
|
|
```php |
|
|
|
|
use yii\db\ActiveRecord; |
|
|
|
|
use yii\web\IdentityInterface; |
|
|
|
|
|
|
|
|
|
class User extends ActiveRecord implements IdentityInterface |
|
|
|
|
{ |
|
|
|
|
public static function findIdentityByAccessToken($token) |
|
|
|
|
{ |
|
|
|
|
return static::find(['access_token' => $token]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
After authentication is enabled as described above, for every API request, the requested controller |
|
|
|
|
will try to authenticate the user in its `beforeAction()` step. |
|
|
|
|
|
|
|
|
|
If authentication succeeds, the controller will perform other checks (such as rate limiting, authorization) |
|
|
|
|
and then run the action. The authenticated user identity information can be retrieved via `Yii::$app->user->identity`. |
|
|
|
|
|
|
|
|
|
If authentication fails, a response with HTTP status 401 will be sent back together with other appropriate headers |
|
|
|
|
(such as a `WWW-Authenticate` header for HTTP Basic Auth). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Authorization |
|
|
|
|
------------- |
|
|
|
|
|
|
|
|
|
After a user is authenticated, you probably want to check if he has the permission to perform the requested |
|
|
|
|
action for the requested resource. This process is called *authorization* which is covered in detail in |
|
|
|
|
the [Authorization chapter](authorization.md). |
|
|
|
|
|
|
|
|
|
Versioning |
|
|
|
|
---------- |
|
|
|
|
You may use the [[yii\web\AccessControl]] filter and/or the Role-Based Access Control (RBAC) component |
|
|
|
|
to implementation authorization. |
|
|
|
|
|
|
|
|
|
To simplify the authorization check, you may also override the [[yii\rest\Controller::checkAccess()]] method |
|
|
|
|
and then call this method in places where authorization is needed. By default, the built-in actions provided |
|
|
|
|
by [[yii\rest\ActiveController]] will call this method when they are about to run. |
|
|
|
|
|
|
|
|
|
Caching |
|
|
|
|
------- |
|
|
|
|
```php |
|
|
|
|
/** |
|
|
|
|
* Checks the privilege of the current user. |
|
|
|
|
* |
|
|
|
|
* This method should be overridden to check whether the current user has the privilege |
|
|
|
|
* to run the specified action against the specified data model. |
|
|
|
|
* If the user does not have access, a [[ForbiddenHttpException]] should be thrown. |
|
|
|
|
* |
|
|
|
|
* @param string $action the ID of the action to be executed |
|
|
|
|
* @param \yii\base\Model $model the model to be accessed. If null, it means no specific model is being accessed. |
|
|
|
|
* @param array $params additional parameters |
|
|
|
|
* @throws ForbiddenHttpException if the user does not have access |
|
|
|
|
*/ |
|
|
|
|
public function checkAccess($action, $model = null, $params = []) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rate Limiting |
|
|
|
|
------------- |
|
|
|
|
|
|
|
|
|
To prevent abuse, you should consider adding rate limiting to your APIs. For example, you may limit the API usage |
|
|
|
|
of each user to be at most 100 API calls within a period of 10 minutes. If too many requests are received from a user |
|
|
|
|
within the period of the time, a response with status code 429 (meaning Too Many Requests) should be returned. |
|
|
|
|
|
|
|
|
|
To enable rate limiting, the [[yii\web\User::identityClass|user identity class]] should implement [[yii\rest\RateLimitInterface]]. |
|
|
|
|
This interface requires implementation of the following three methods: |
|
|
|
|
|
|
|
|
|
* `getRateLimit()`: returns the maximum number of allowed requests and the time period, e.g., `[100, 600]` means |
|
|
|
|
at most 100 API calls within 600 seconds. |
|
|
|
|
* `loadAllowance()`: returns the number of remaining requests allowed and the corresponding UNIX timestamp |
|
|
|
|
when the rate limit is checked last time. |
|
|
|
|
* `saveAllowance()`: saves the number of remaining requests allowed and the current UNIX timestamp. |
|
|
|
|
|
|
|
|
|
You may use two columns in the user table to record the allowance and timestamp information. |
|
|
|
|
And `loadAllowance()` and `saveAllowance()` can then be implementation by reading and saving the values |
|
|
|
|
of the two columns corresponding to the current authenticated user. To improve performance, you may also |
|
|
|
|
consider storing these information in cache or some NoSQL storage. |
|
|
|
|
|
|
|
|
|
Once the identity class implements the required interface, Yii will automatically use the rate limiter |
|
|
|
|
as specified by [[yii\rest\Controller::rateLimiter]] to perform rate limiting check. The rate limiter |
|
|
|
|
will thrown a [[yii\web\TooManyRequestsHttpException]] if rate limit is exceeded. |
|
|
|
|
|
|
|
|
|
When rate limiting is enabled, every response will be sent with the following HTTP headers containing |
|
|
|
|
the current rate limiting information: |
|
|
|
|
|
|
|
|
|
* `X-Rate-Limit-Limit`: The maximum number of requests allowed with a time period; |
|
|
|
|
* `X-Rate-Limit-Remaining`: The number of remaining requests in the current time period; |
|
|
|
|
* `X-Rate-Limit-Reset`: The number of seconds to wait in order to get the maximum number of allowed requests. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Caching |
|
|
|
|
------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Error Handling |
|
|
|
|
-------------- |
|
|
|
@ -309,7 +590,7 @@ Error Handling
|
|
|
|
|
* `304`: Resource was not modified. You can use the cached version. |
|
|
|
|
* `400`: Bad request. This could be caused by various reasons from the user side, such as invalid JSON |
|
|
|
|
data in the request body, invalid action parameters, etc. |
|
|
|
|
* `401`: No valid API access token is provided. |
|
|
|
|
* `401`: Authentication failed. |
|
|
|
|
* `403`: The authenticated user is not allowed to access the specified API endpoint. |
|
|
|
|
* `404`: The requested resource does not exist. |
|
|
|
|
* `405`: Method not allowed. Please check the `Allow` header for allowed HTTP methods. |
|
|
|
@ -319,6 +600,10 @@ Error Handling
|
|
|
|
|
* `500`: Internal server error. This could be caused by internal program errors. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Versioning |
|
|
|
|
---------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Documentation |
|
|
|
|
------------- |
|
|
|
|
|
|
|
|
|