Commit 17f4f420 by Qiang Xue

guide WIP [skip ci]

parent 0126a9d5
...@@ -125,12 +125,12 @@ RESTful Web Services ...@@ -125,12 +125,12 @@ RESTful Web Services
* [Resources](rest-resources.md) * [Resources](rest-resources.md)
* [Controllers](rest-controllers.md) * [Controllers](rest-controllers.md)
* [Routing](rest-routing.md) * [Routing](rest-routing.md)
* [Data Formatting](rest-data-formatting.md) * [Response Formatting](rest-response-formatting.md)
* [Authentication](rest-authentication.md) * [Authentication](rest-authentication.md)
* [Rate Limiting](rest-rate-limiting.md) * [Rate Limiting](rest-rate-limiting.md)
* [Versioning](rest-versioning.md) * [Versioning](rest-versioning.md)
* [Caching](rest-caching.md)
* [Error Handling](rest-error-handling.md) * [Error Handling](rest-error-handling.md)
* [Caching](rest-caching.md)
Development Tools Development Tools
......
Authentication Authentication
-------------- ==============
Unlike Web applications, RESTful APIs should be stateless, which means sessions or cookies should not 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 be used. Therefore, each request should come with some sort of authentication credentials because
...@@ -33,23 +33,21 @@ To enable authentication for your APIs, do the following two steps: ...@@ -33,23 +33,21 @@ To enable authentication for your APIs, do the following two steps:
For example, to use HTTP Basic Auth, you may configure `authenticator` as follows, For example, to use HTTP Basic Auth, you may configure `authenticator` as follows,
```php ```php
use yii\helpers\ArrayHelper;
use yii\filters\auth\HttpBasicAuth; use yii\filters\auth\HttpBasicAuth;
public function behaviors() public function behaviors()
{ {
return ArrayHelper::merge(parent::behaviors(), [ $behaviors = parent::behaviors();
'authenticator' => [ $behaviors['authenticator'] = [
'class' => HttpBasicAuth::className(), 'class' => HttpBasicAuth::className(),
], ];
]); return $behaviors;
} }
``` ```
If you want to support all three authentication methods explained above, you can use `CompositeAuth` like the following, If you want to support all three authentication methods explained above, you can use `CompositeAuth` like the following,
```php ```php
use yii\helpers\ArrayHelper;
use yii\filters\auth\CompositeAuth; use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBasicAuth; use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth; use yii\filters\auth\HttpBearerAuth;
...@@ -57,16 +55,16 @@ use yii\filters\auth\QueryParamAuth; ...@@ -57,16 +55,16 @@ use yii\filters\auth\QueryParamAuth;
public function behaviors() public function behaviors()
{ {
return ArrayHelper::merge(parent::behaviors(), [ $behaviors = parent::behaviors();
'authenticator' => [ $behaviors['authenticator'] = [
'class' => CompositeAuth::className(), 'class' => CompositeAuth::className(),
'authMethods' => [ 'authMethods' => [
HttpBasicAuth::className(), HttpBasicAuth::className(),
HttpBearerAuth::className(), HttpBearerAuth::className(),
QueryParamAuth::className(), QueryParamAuth::className(),
], ],
], ];
]); return $behaviors;
} }
``` ```
...@@ -100,33 +98,13 @@ If authentication fails, a response with HTTP status 401 will be sent back toget ...@@ -100,33 +98,13 @@ If authentication fails, a response with HTTP status 401 will be sent back toget
(such as a `WWW-Authenticate` header for HTTP Basic Auth). (such as a `WWW-Authenticate` header for HTTP Basic Auth).
Authorization Authorization <a name="authorization"></a>
------------- -------------
After a user is authenticated, you probably want to check if he has the permission to perform the requested After a user is authenticated, you probably want to check if he or she has the permission to perform the requested
action for the requested resource. This process is called *authorization* which is covered in detail in action for the requested resource. This process is called *authorization* which is covered in detail in
the [Authorization section](authorization.md). the [Authorization section](authorization.md).
You may use the Role-Based Access Control (RBAC) component to implementation authorization. If your controllers extend from [[yii\rest\ActiveController]], you may override
the [[yii\rest\Controller::checkAccess()|checkAccess()]] method to perform authorization check. The method
To simplify the authorization check, you may also override the [[yii\rest\Controller::checkAccess()]] method will be called by the built-in actions provided by [[yii\rest\ActiveController]].
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.
```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 = [])
{
}
```
Controllers Controllers
=========== ===========
So you have the resource data and you have specified how the resource data should be formatted, the next thing After creating the resource classes and specifying how resource data should be formatted, the next thing
to do is to create controller actions to expose the resource data to end users. to do is to create controller actions to expose the resources to end users through RESTful APIs.
Yii provides two base controller classes to simplify your work of creating RESTful actions: 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 [[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 is that the latter provides a default set of actions that are specifically designed to deal with
resources represented as ActiveRecord. So if you are using ActiveRecord and you are comfortable with resources represented as [Active Record](db-active-record.md). So if you are using [Active Record](db-active-record.md)
the provided built-in actions, you may consider creating your controller class by extending from and are comfortable with the provided built-in actions, you may consider extending your controller classes
the latter. Otherwise, extending from [[yii\rest\Controller]] will allow you to develop actions from [[yii\rest\ActiveController]], which will allow you to create powerful RESTful APIs with minimal code.
from scratch.
Both [[yii\rest\Controller]] and [[yii\rest\ActiveController]] provide the following features which will Both [[yii\rest\Controller]] and [[yii\rest\ActiveController]] provide the following features, some of which
be described in detail in the next few sections: will be described in detail in the next few sections:
* Response format negotiation;
* API version negotiation;
* HTTP method validation; * HTTP method validation;
* User authentication; * [Content negotiation and Data formatting](rest-response-formatting.md);
* Rate limiting. * [Authentication](rest-authentication.md);
* [Rate limiting](rest-rate-limiting.md).
[[yii\rest\ActiveController]] in addition provides the following features specifically for working [[yii\rest\ActiveController]] in addition provides the following features:
with ActiveRecord:
* A set of commonly used actions: `index`, `view`, `create`, `update`, `delete`, `options`; * A set of commonly needed actions: `index`, `view`, `create`, `update`, `delete`, `options`;
* User authorization in regard to the requested action and resource. * User authorization in regarding to the requested action and resource.
Creating Controller Classes
---------------------------
When creating a new controller class, a convention in naming the controller class is to use 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 type name of the resource and use singular form. For example, to serve user information,
...@@ -38,19 +39,65 @@ you directly return the data. The [[yii\rest\Controller::serializer|serializer]] ...@@ -38,19 +39,65 @@ you directly return the data. The [[yii\rest\Controller::serializer|serializer]]
format. For example, format. For example,
```php ```php
public function actionSearch($keyword) public function actionView($id)
{ {
$result = SolrService::search($keyword); return User::findOne($id);
return $result;
} }
``` ```
Filters
-------
Most RESTful API features provided by [[yii\rest\Controller]] are implemented in terms of [filters](runtime-filtering.md).
In particular, the following filters will be executed in the order they are listed:
* [[yii\filters\ContentNegotiator|contentNegotiator]]: supports content negotiation, to be explained in
the [Response Formatting](rest-response-formatting.md) section;
* [[yii\filters\VerbFilter|verbFilter]]: supports HTTP method validation;
* [[yii\filters\AuthMethod|authenticator]]: supports user authentication, to be explained in
the [Authentication](rest-authentication.md) section;
* [[yii\filters\RateLimiter|rateLimiter]]: supports rate limiting, to be explained in
the [Rate Limiting](rest-rate-limiting.md) section.
These named filters are declared in the [[yii\rest\Controller::behaviors()|behaviors()]] method.
You may override this method to configure individual filters, disable some of them, or add your own filters.
For example, if you only want to use HTTP basic authentication, you may write the following code:
```php
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::className(),
];
return $behaviors;
}
```
Extending `ActiveController`
----------------------------
If your controller class extends from [[yii\rest\ActiveController]], you should set 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 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]]. that you plan to serve through this controller. The class must extend from [[yii\db\ActiveRecord]].
### Customizing Actions
By default, [[yii\rest\ActiveController]] provides the following actions:
* [[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.
With [[yii\rest\ActiveController]], you may want to disable some of the built-in actions or customize them. All these actions are declared through the [[yii\rest\ActiveController::actions()|actions()]] method.
To do so, override the `actions()` method like the following: You may configure these actions or disable some of them by overriding the `actions()` method, like shown the following,
```php ```php
public function actions() public function actions()
...@@ -72,12 +119,36 @@ public function prepareDataProvider() ...@@ -72,12 +119,36 @@ public function prepareDataProvider()
} }
``` ```
The following list summarizes the built-in actions supported by [[yii\rest\ActiveController]]: Please refer to the class references for individual action classes to learn what configuration options are available.
* [[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.
### Performing Access Check
When exposing resources through RESTful APIs, you often need to check if the current user has the permission
to access and manipulate the requested resource(s). With [[yii\rest\ActiveController]], this can be done
by overriding the [[yii\rest\ActiveController::checkAccess()|checkAccess()]] method like the following,
```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 = [])
{
// check if the user can access $action and $model
// throw ForbiddenHttpException if access should be denied
}
```
The `checkAccess()` method will be called by the default actions of [[yii\rest\ActiveController]]. If you create
new actions and also want to perform access check, you should call this method explicitly in the new actions.
> Tip: You may implement `checkAccess()` by using the [Role-Based Access Control (RBAC) component](security-authorization.md).
Error Handling Error Handling
-------------- ==============
When handling a RESTful API request, if there is an error in the user request or if something unexpected When handling a RESTful API request, if there is an error in the user request or if something unexpected
happens on the server, you may simply throw an exception to notify the user something wrong happened. happens on the server, you may simply throw an exception to notify the user that something wrong has happened.
If you can identify the cause of the error (e.g. the requested resource does not exist), you should If you can identify the cause of the error (e.g. the requested resource does not exist), you should
consider throwing an exception with a proper HTTP status code (e.g. [[yii\web\NotFoundHttpException]] consider throwing an exception with a proper HTTP status code (e.g. [[yii\web\NotFoundHttpException]]
representing a 404 HTTP status code). Yii will send the response with the corresponding HTTP status representing a 404 HTTP status code). Yii will send the response with the corresponding HTTP status
......
...@@ -157,7 +157,7 @@ For example, the URL `http://localhost/users?fields=id,email` will only return t ...@@ -157,7 +157,7 @@ For example, the URL `http://localhost/users?fields=id,email` will only return t
> Info: You may have noticed that the result of `http://localhost/users` includes some sensitive fields, > Info: You may have noticed that the result of `http://localhost/users` includes some sensitive fields,
> such as `password_hash`, `auth_key`. You certainly do not want these to appear in your API result. > such as `password_hash`, `auth_key`. You certainly do not want these to appear in your API result.
> You can and should filter out these fields as described in the [Data Formatting](rest-data-formatting.md) section. > You can and should filter out these fields as described in the [Response Formatting](rest-response-formatting.md) section.
Summary Summary
......
Rate Limiting Rate Limiting
------------- =============
To prevent abuse, you should consider adding rate limiting to your APIs. For example, you may limit the API usage 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 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
...@@ -25,17 +25,11 @@ will thrown a [[yii\web\TooManyRequestsHttpException]] if rate limit is exceeded ...@@ -25,17 +25,11 @@ will thrown a [[yii\web\TooManyRequestsHttpException]] if rate limit is exceeded
as follows in your REST controller classes, as follows in your REST controller classes,
```php ```php
use yii\helpers\ArrayHelper;
use yii\filters\RateLimiter;
public function behaviors() public function behaviors()
{ {
return ArrayHelper::merge(parent::behaviors(), [ $behaviors = parent::behaviors();
'rateLimiter' => [ $behaviors['rateLimiter']['enableRateLimitHeaders'] = false;
'class' => RateLimiter::className(), return $behaviors;
'enableRateLimitHeaders' => false,
],
]);
} }
``` ```
......
...@@ -27,7 +27,8 @@ When a resource object is sent in response to a RESTful API request, it involves ...@@ -27,7 +27,8 @@ When a resource object is sent in response to a RESTful API request, it involves
1. The object is converted into an array by [[yii\rest\Serializer]]. This is the focus of this section. 1. The object is converted into an array by [[yii\rest\Serializer]]. This is the focus of this section.
2. The array is serialized into a string in a requested format (e.g. JSON, XML) by 2. The array is serialized into a string in a requested format (e.g. JSON, XML) by
[[yii\web\ResponseFormatterInterface|response formatters]]. This will be the focus of the next section. [[yii\web\ResponseFormatterInterface|response formatters]]. This will be the focus of
the [Response Formatting](rest-response-formatting.md) section.
By overriding [[yii\base\Model::fields()|fields()]] and/or [[yii\base\Model::extraFields()|extraFields()]], By overriding [[yii\base\Model::fields()|fields()]] and/or [[yii\base\Model::extraFields()|extraFields()]],
you may specify what data, called *fields*, in the resource can be put in the array representation of a resource object. you may specify what data, called *fields*, in the resource can be put in the array representation of a resource object.
......
Data Formatting Response Formatting
=============== ===================
As described in the [Resources](rest-resources.md) section, we have shown how to specify what data a resource
can expose through RESTful APIs. In this section, we will describe the behind-the-scene work regarding how a
resource is being turned into a string in the format that is requested by end users. We will also describe
the possible options that you have in order to customize this process.
individual
there are two steps involved in formatting response data.
The first step is to convert resources or resource collections into arrays, and the second step is to serialize
the arrays into strings in the requested format. The first step has been covered in the [Resources](rest-resources.md)
section. In this section, we will mainly describe the second step.
By default, Yii supports two response formats for RESTful APIs: JSON and XML. If you want to support By default, Yii supports two response formats for RESTful APIs: JSON and XML. If you want to support
other formats, you should configure the `contentNegotiator` behavior in your REST controller classes as follows, other formats, you should configure the `contentNegotiator` behavior in your REST controller classes as follows,
......
Routing Routing
------- =======
With resource and controller classes ready, you can access the resources using the URL like 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 `http://localhost/index.php?r=user/create`, similar to what you can do with normal Web applications.
for Web applications.
In practice, you usually want to enable pretty URLs and take advantage of HTTP verbs. 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. For example, a request `POST /users` would mean accessing the `user/create` action.
......
API Versioning Versioning
-------------- ==========
Your APIs should be versioned. Unlike Web applications which you have full control on both client side and server side Your APIs should be versioned. Unlike Web applications which you have full control on both client side and server side
code, for APIs you usually do not have control of the client code that consumes the APIs. Therefore, backward code, for APIs you usually do not have control of the client code that consumes the APIs. Therefore, backward
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment