REST API
An API is a set of URLs through which a program, not a person, talks to the site: a mobile application or a script in a browser. REST is a convention for such URLs: GET /posts returns a list, POST /posts creates a record, DELETE /posts/5 deletes one. In Yii the yii\rest\ActiveController class gives a ready-made API for a model.
The API controller
To keep the API apart from site pages, the controller is put into a subfolder. Create the folder controllers/api by hand and a file in it:
// controllers/api/PostController.php
namespace app\controllers\api;
use yii\rest\ActiveController;
class PostController extends ActiveController
{
public $modelClass = 'app\models\Post';
}No more code is needed: the actions for listing, viewing, creating, updating and deleting are already in ActiveController. The route of a controller in a subfolder is api/post.
The URL rule
Add to the rules of the urlManager component in config/web.php:
// config/web.php
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => 'api/post'],
// the other rules
],One rule creates the whole set of URLs. The controller name is pluralized in the URL: api/posts.
| Request | What it does |
|---|---|
GET /api/posts | The list of posts |
GET /api/posts/5 | One post |
POST /api/posts | Create |
PUT /api/posts/5 | Update |
DELETE /api/posts/5 | Delete |
Checking
curl http://localhost:8080/api/postsThe command prints an array of posts in JSON. The list is served in pages of 20 records; the total number comes in the X-Pagination-Total-Count response header, and the next page is /api/posts?page=2.
Accepting JSON
For the API to accept data in JSON, enable the parser in the request component:
// config/web.php
'request' => [
'cookieValidationKey' => '...',
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
],Now a post can be created with a request:
curl -X POST http://localhost:8080/api/posts \
-H "Content-Type: application/json" \
-d '{"title": "From the API", "body": "Text of the post"}'The response is the created post and code 201. If the data does not pass the model rules, code 422 and a list of errors by field come back.
Choosing fields
By default all table columns get into the response. The list of fields is set by the fields() method of the model:
// models/Post.php
public function fields(): array
{
return [
'id',
'title',
'body',
'published' => fn () => (bool) $this->status,
];
}Four fields remain in the response, and published is calculated by a function. This method matters most for the User model: without it the API would return password_hash.
Access by key
Right now anyone can create and delete a post. Access is closed with an authentication filter:
// controllers/api/PostController.php
use yii\filters\auth\HttpBearerAuth;
public function behaviors(): array
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = ['class' => HttpBearerAuth::class];
return $behaviors;
}The filter takes the key from the Authorization: Bearer ... header and passes it to the User::findIdentityByAccessToken() method. That method must find a user by the key, for example by a separate access_token column. A request without a valid key gets code 401.
Common mistake
If you open /api/posts in a browser, XML arrives, not JSON. Nothing is broken: Yii chooses the format by the Accept header, and a browser asks for XML. Programs that send Accept: application/json, as well as curl, receive JSON.