Yii provides two base classes: yii
estController
and yii
estActiveController
that we can extend when we are creating a new controller for RESTful web services.
Both of these classes contain the following useful common features, in execution order:
The second class yii
estActiveController
adds more functionalities through ActiveRecord, such as handling user authorization and a set of already existing actions: index
, view
, create
, update
, delete
, and options
.
We will see that Yii provides all the necessary information to get the response status and content through the body and HTTP header.
Let's create a controller to extend yii
estController
or rather without ActiveRecord. Create a new controller in api/controllers/TestRestController.php
:
<?php namespace apicontrollers; use yii estController; class TestRestController extends Controller { private function dataList() { return [ [ 'id' => 1, 'name' => 'Albert', 'surname' => 'Einstein' ], [ 'id' => 2, 'name' => 'Enzo', 'surname' => 'Ferrari' ], [ 'id' => 4, 'name' => 'Mario', 'surname' => 'Bros' ] ]; } public function actionIndex() { return $this->dataList(); } }
In the preceding code, we have a method dataList
, which returns an array of objects, and an actionIndex
method that provides the index
action for TestRestController
and returns that list.
The first feature of yii
estController
is to arrange the response output format, dynamically based on the request, which is also called content negotiation.
Indeed, we can try to launch this request through http://hostname/yiiadv/api/web/test-rest/index
in our browser, or through specific tools using the GET verb and the Accept
HTTP header set to application/xml
, or by using curl
, as follows:
$ curl -H "Accept: application/xml" http://hostname/yiiadv/api/web/test-rest/index <?xml version="1.0" encoding="UTF-8"?> <response><item><id>1</id><name>Albert</name><surname>Einstein</surname></item><item><id>2</id><name>Enzo</name><surname>Ferrari</surname></item><item><id>4</id><name>Mario</name><surname>Bros</surname></item></response>
In these cases, we will get a response based on the XML data:
However, if we change the Accept
header to application/json
, we will get a response based on the JSON data:
$ curl -H "Accept: application/json" http://hostname/yiiadv/api/web/test-rest/index [{"id":1,"name":"Albert","surname":"Einstein"},{"id":2,"name":"Enzo","surname":"Ferrari"},{"id":4,"name":"Mario","surname":"Bros"}]
In these cases, we will get a response based on the JSON data:
The same data will be rendered in different ways according to the Accept
header sent from the client.
The second feature, HTTP method validation, allows you to specify which verbs are available for a resource. Verbs are defined in the behaviors()
method, which must be extended to modify this setting:
public function behaviors() { $behaviors = parent::behaviors(); $behaviors['verbs'] = [ 'class' => yiifiltersVerbFilter::className(), 'actions' => [ 'index' => ['get'], ], ]; return $behaviors; }
In this case, we only set the GET verb to the index
action, because keys of the actions
attribute of behaviors['verbs']
are the actions and the value is an array containing supported HTTP methods.
If we launch http://hostname/yiiadv/api/web/test-rest/index
using the GET verb (as a browser request), we will continue to display the result. However, if we change the HTTP method to the POST verb, for example, we will get an exception error:
This is because only the GET verb is supported by the index
action.
In the next sections, we will explain the third and fourth features, authentication and rate limiting.
With this example, we will apply the concepts dealt with in the previous chapter, in this case using yii
estActiveController
as the base class instead of yii
estController
, since we are going to employ an ActiveRecord class to manipulate data.
Create a new controller in api/controllers/RoomsController.php
:
<?php namespace apicontrollers; use yii estActiveController; class RoomsController extends ActiveController { public $modelClass = 'commonmodelsRoom'; }
This controller implicitly contains these actions:
actionIndex
that returns a list of models, accessible only with GET and HEAD HTTP methodsactionView
that returns details about the mode, accessible only with the GET and HEAD HTTP methods by passing the id
parameteractionCreate
that creates a new model, accessible only with the POST HTTP methodsactionUpdate
that updates an existing model, accessible only with the PUT and PATCH HTTP methodsactionDelete
that deletes an existing model, accessible only with the DELETE HTTP methodactionOptions
that returns the allowed HTTP methodsNow, let's try to launch all these methods.
Launch actionIndex
at http://hostname/yiiadv/api/web/rooms
using the GET method:
[ { "id": 1, "floor": 1, "room_number": 101, "has_conditioner": 1, "has_tv": 0, "has_phone": 1, "available_from": "2015-05-20", "price_per_day": "120.00", "description": "description 1" }, { "id": 2, "floor": 2, "room_number": 202, "has_conditioner": 0, "has_tv": 1, "has_phone": 1, "available_from": "2015-05-30", "price_per_day": "118.00", "description": "description 2" } ]
We will get all the records in the database as an array of the JSON object and HTTP header, along with the successful status code and pagination details:
X-Pagination-Current-Page: 1 X-Pagination-Page-Count: 1 X-Pagination-Per-Page: 20 X-Pagination-Total-Count: 2
If we launch the same URL using the HEAD HTTP method, we will only get the HTTP HEADER response without a body, so we will get only the pagination information.
Finally, if we launch the same URL with an unsupported HTTP method, for example the PUT method, we will get two important HTTP headers:
status code
header set to 405 Method Not Allowed
Allow
header set to GET, HEAD
The status code
header says that a method is not supported, and the Allow
header returns a list of supported HTTP methods for that action.
Now, launch actionView
on http://hostname/yiiadv/api/web/rooms/view?id=1
using the GET method:
{ "id": 1, "floor": 1, "room_number": 101, "has_conditioner": 1, "has_tv": 0, "has_phone": 1, "available_from": "2015-05-20", "price_per_day": "120.00", "description": "description 1" }
If we try to launch a nonexistent ID, for example http://hostname/yiiadv/api/web/rooms/view?id=100
, using the GET method, we will get this body response:
{ "name": "Not Found", "message": "Object not found: 100", "code": 0, "status": 404, "type": "yii\\web\\NotFoundHttpException" }
The HTTP status code
header will be set to 404 Not Found
to specify that the requested item (id=100
) does not exist. Using only the HEAD HTTP method, we will get information from the HTTP status code
set to 404
. The Create
and Update
actions require that the client sends body content of the object to be created or updated.
By default, Yii recognizes only the application/x-www-form-urlencoded
and multipart/form-data
input formats. In order to enable the JSON input format, we need to configure the parsers
property of the request's application component in the api/config/main.php
file:
'request' => [ 'parsers' => [ 'application/json' => 'yiiwebJsonParser', ] ]
After configuring the JSON input parser, we can call http://hostname/yiiadv/api/web/rooms/create
using the POST HTTP method to create a new room and pass, for example, this JSON:
{ "floor": 99, "room_number": 999, "has_conditioner": 1, "has_tv": 1, "has_phone": 1, "available_from": "2015-12-30", "price_per_day": "48.00", "description": "description room 999" }
If no error occurred, we will get:
201 Created as HTTP Header Status Code Object just created as body content
If we are missing some required fields and there are validation errors, we will get:
422 Data Validation Failed An array of field-message to indicate which validation errors occurred
The same thing needs to be done for an update action, in this case, however, we will call http://hostname/yiiadv/api/web/rooms/update
and pass the id
URL parameter using the PUT or PATCH HTTP method. In this case, only the HTTP header status code 200 OK
will be a successful response and the update object will be returned as body content.
Finally, actionDelete
is used by calling http://hostname/yiiadv/api/web/rooms/delete
, by passing the id
URL parameter, and using the DELETE HTTP method. A successful execution will return 204 No Content
as the HTTP status code; otherwise, it will be 404 Not Found
.
3.135.183.89