Not long ago to do a project, is to use the YII2 framework to write a restful style of API, went to the next "YII 2.0 authoritative Guide", found that the above is written relatively brief. So just write a tutorial post here to help you get started quickly with a small partner who has just come into contact with YII2 framework restful.
I. Directory structure
The implementation of a simple RESTful API requires only three files. The directory is as follows:
Frontend ├─config │ └main.php ├─controllers │ └bookcontroller.php └─models └ book.php
Second, configure the URL rules
1. Modify the server's rewrite rule to point all URLs to index.php to support the/BOOKS/1 format.
If it is an Apache server, create a new. htaccess file in the frontend/web/directory. The contents of the file are as follows:
Rewriteengine on# If A directory or a file exists, use the request directly Rewritecond%{request_filename}!-f Re Writecond%{request_filename}!-d# Otherwise forward the REQUEST to index.php rewriterule . index.php
If it is an nginx server, modify nginx/conf/nginx.conf to add the following red tag content in the "location/{}" of the current "server{}":
Location/{try_files $uri $uri//index.php$is_args$args;}
2. Modify the frontend/config/main.php file to add a URL rule for the book controller. In this way, the data can be accessed and manipulated through a glorified URL and meaningful HTTP verbs. The configuration is as follows:
' Components ' = [ ' urlmanager ' + [' enableprettyurl ' = ' = ', ' enablestrictparsing ' and ' = true,< c8/> ' Showscriptname ' + false, ' rules ' = [ ' class ' = ' Yii\rest\urlrule ', ' Controller ' and ' book ' ], ], ],],
Third, create a model
1. Create a book table in the database. The contents of the Book table are as follows:
--------------------------------table structure------------------------------DROP table IF EXISTS ' book '; CREATE TABLE ' book ' ( ' id ' int ($) unsigned NOT NULL auto_increment, ' name ' char (a) ' NOT null DEFAULT ' ', ' num ' tinyint (3) unsigned not NULL default ' 0 ', PRIMARY KEY (' id ')) engine=innodb auto_increment=6 default charset=utf8;-- ------------------------------Records of book------------------------------INSERT to ' book ' VALUES (' 1 ', ' TOEFL ', ' 1 0 '); insert INTO ' book ' Values (' 2 ', ' ielts ', ' ' + '); insert INTO ' book ' Values (' 3 ', ' sat ', ' + '); insert INTO ' book ' Values (' 4 ', ' GRE ', ' + '); INSERT into ' book ' VALUES (' 5 ', ' GMAT ', ' 50 ');
2. Create a new book.php in the frontend/models/directory. The contents of the file are as follows:
Namespace Frontend\models;use yii\db\activerecord;class Book extends activerecord{public static function TableName () { return ' book '; }}
Iv. Creating a Controller
Create a new bookcontroller.php in the frontend/controllers/directory. The controller class extends from Yii\rest\activecontroller. By specifying Yii\rest\activecontroller::modelclass as the Frontend\models\book, the controller can know which model to use to acquire and manipulate the data. The contents of the file are as follows:
Namespace Frontend\controllers;use yii\rest\activecontroller;class Bookcontroller extends activecontroller{ Public $modelClass = ' Frontend\models\book ';}
V. Testing
Here we have finished creating RESTful-style APIs for accessing user data. The APIs created include:
Get/books: List all books Head/books: A summary of the list of displayed books Post/books: Added 1 books get/books/1: Return to book id=1 details HEAD/BOOKS/1: Display book id=1 overview information Patch/ BOOKS/1 and PUT/BOOKS/1: More book id=1 info delete/books/1: Delete book id=1 info options/books: Show verbs about end/books support OPTIONS/BOOKS/1: Show about End Verbs supported by/BOOKS/1
You can access the API by entering the URL Http://{frontend's domain name}/books in your Web browser, or by using some browser plugins to send specific headers requests, such as Firefox restclient, Chrome's Advanced Rest Client, Postman, and more.
Vi. description
1.Yii the name of the controller to be used at the end automatically becomes the plural. This is because the yii\rest\urlrule can be used for their end-automatic complex controller. You can disable this behavior by setting Yii\rest\urlrule::p luralize to False:
' Rules ' = [ ' class ' = ' Yii\rest\urlrule ', ' controller ' = ' book ', ' Pluralize ' and false],
2. You can use the fields and expand parameters to specify which field should be included within the result. For example, the name of the URL Http://{frontend}/books?fields=name,num will return only the name and Num fields.
Today, let's explore the YII2 RESTful format response, authorization authentication and rate limiting three parts
I. Directory structure
First, list the files that need to be changed. The directory is as follows:
web├─common│ └─models │ └user.php└─frontend ├─config │ └main.php └─controllers └bookcontroller.php
Second, formatted response
YII2 restful supports JSON and XML formats, and if you want to specify the format of the returned data, you need to configure the Yii\filters\contentnegotiator::formats property. For example, to return the JSON format, modify the frontend/controllers/bookcontroller.php, and add the Red Tag code:
namespace Frontend\controllers;use yii\rest\activecontroller;use Yii\web\response;class BookController extends activecontroller{public $modelClass = ' Frontend\models\book '; Public Function Behaviors () { $behaviors = parent::behaviors (); $behaviors [' Contentnegotiator '] [' formats '] [' text/html '] = Response::format_json; return $behaviors; }}
Returns the XML format: Format_xml. The keys for the Formats property support MIME types, and values must support the response format name in Yii\web\response::formatters.
Third, authorized certification
RESTful APIs are usually stateless, so each request should be accompanied by some kind of authorization credential, that is, each request sends an access token to authenticate the user.
1. Configure the User application component (not necessary, but recommended):
Set the Yii\web\user::enablesession property to False (because the restful APIs are stateless, and when Yii\web\user::enablesession is false, The user authentication status in the request cannot be maintained by the session)
Set the Yii\web\user::loginurl property to Null (displays an HTTP 403 error instead of jumping to the login interface)
Specific methods, modify frontend/config/main.php, add red Tag code:
' Components ' = [ ... ' User ' = ' + [ ' identityclass ' = ' common\models\user ', ' enableautologin ' = ' = ', ' enablesession ' = > False, ' loginurl ' = null, ], ...]
2. Configure the authenticator behavior in the controller class to specify which authentication method to use, modify the frontend/controllers/bookcontroller.php, and add the Red Tag code:
namespace Frontend\controllers;use yii\rest\activecontroller;use Yii\web\response;use yii\filters\auth\ Compositeauth;use Yii\filters\auth\queryparamauth;class Bookcontroller extends activecontroller{public $modelClass = ' Frontend\models\book '; Public Function Behaviors () {$behaviors = Parent::behaviors (); $behaviors [' authenticator '] = [' class ' = = Compositeauth::classname (), ' authmethods ' = [ /* Below are three ways to verify Access_token *///1.http Basic Authentication: Access token is sent as a user name, and is applied in a scenario where access token can safely exist on the API usage, for example, A The PI usage is a program that runs on a single server. Httpbasicauth::classname (),//2.oauth 2: The user obtains the OAUTH2 protocol-based access token from the authentication server and then sends it to a via HTTP Bearer Tokens PI server. Httpbearerauth::classname (),//3. Request Parameters: Access token is sent as an API URL request parameter, which should be used primarily for JSONP requests because it cannot be sent using an HTTP header acces S token//http://localhost/user/index/index?access-token=123 queryparamauth::classname (), ], ]; $behaviors [' Contentnegotiator '] [' formats '] [' text/html '] = Response::format_json; return $behaviors; }}
3. Create a user table
--------------------------------table structure for user------------------------------DROP table IF EXISTS ' user '; CREATE TABLE ' user ' (' id ' int () unsigned not NULL auto_increment, ' username ' varchar () ' "Not null DEFAULT ' COMMENT ' username ', ' password_hash ' varchar (+) NOT null DEFAULT ' COMMENT ' password ', ' password_reset_token ' varchar (NOT NULL Defaul T ' COMMENT ' password token ', ' email ' varchar (+) NOT null default ' COMMENT ' mailbox ', ' auth_key ' varchar (NOT NULL default ') ' , ' status ' tinyint (3) unsigned NOT NULL default ' 0 ' COMMENT ' state ', ' created_at ' int (ten) unsigned NOT null default ' 0 ' COM ment ' creation time ', ' updated_at ' int (ten) unsigned NOT null DEFAULT ' 0 ' COMMENT ' update Time ', ' access_token ' varchar (NOT NULL DEFA ULT ' COMMENT ' restful request token ', ' allowance ' int (ten) unsigned not NULL DEFAULT ' 0 ' COMMENT ' restful remaining number of allowed requests ', ' Allowanc E_updated_at ' int (ten) unsigned not NULL DEFAULT ' 0 ' COMMENT ' RESTful request unix timestamp number ', PRIMARY key (' id '), UNIQUE KEY ' Userna Me ' (' username '), UNIQUE KEY ' Access_token ' (' Access_token ')) Engine=innodb DEFAULT Charset=utf8;--------------------------------Records of User------------------------------INSERT into ' user ' VALUES (' 1 ', ' admin ', ' $2y$13$ 1kwwchqgvxdeordt5prw.ojarf06pjnyxe2vegvs7e5amd3wnex.i ', ', ', ' Z3SM2KZVXDK6MNXXRZ25D3JOZLGXOJMC ', ' 10 ', ' 1478686493 ', ' 1478686493 ', ' 123 ', ' 4 ', ' 1478686493 ');
Implement the Yii\web\identityinterface::findidentitybyaccesstoken () method in the Common/models/user.php class. To modify the common/models/user.php, add the red tag code:
public static function Findidentitybyaccesstoken ($token, $type = null) The implementation of the {//findidentitybyaccesstoken () method is a system-defined ///For example, in a simple scenario, when each user has only one access token, the access token can be stored in the Access_token column of the user table, and the method can be easily implemented in the user class as follows: return Static::findone ([' access_token ' = $token]); throw new NotSupportedException (' "Findidentitybyaccesstoken" is not implemented. ');}
Iv. Rate Limits
To prevent abuse, you can increase the rate limit. For example, restricting the use of each user's API is a maximum of 10 API calls within 60 seconds, and if a user receives too many requests within the same time period, the response status Code 429 (which means too many requests) is returned.
1.Yii automatically configures a behavior filter for Yii\rest\controller using Yii\filters\ratelimiter to perform rate limit checks. If the speed exceeds the limit, the rate limiter will throw a yii\web\toomanyrequestshttpexception.
Modify frontend/controllers/bookcontroller.php, add red Tag code:
namespace Frontend\controllers;use yii\rest\activecontroller;use Yii\web\response;use yii\filters\auth\ Compositeauth;use yii\filters\auth\queryparamauth;use Yii\filters\ratelimiter;class BookController extends activecontroller{Public $modelClass = ' Frontend\models\book '; Public Function Behaviors () {$behaviors = Parent::behaviors (); $behaviors [' ratelimiter '] = [' class ' = = Ratelimiter::classname (), ' enableratelimitheaders ' = True,]; $behaviors [' authenticator '] = [' class ' = = Compositeauth::classname (), ' authmethods ' = [ /* Below are three ways to verify Access_token *///1.http Basic Authentication: Access token is sent as a user name, and is applied in a scenario where access token can safely exist on the API usage, for example, A The PI usage is a program that runs on a single server. Httpbasicauth::classname (),//2.oauth 2: The user obtains the OAUTH2 protocol-based access token from the authentication server and then sends it to a via HTTP Bearer Tokens PI server. Httpbearerauth::classname (),//3. Request parameters: ACcess token is sent as an API URL request parameter, which should be used primarily for JSONP requests because it cannot use HTTP headers to send access tokens//http://localhost/user/index/inde X?access-token=123 Queryparamauth::classname (),],]; $behaviors [' Contentnegotiator '] [' formats '] [' text/html '] = Response::format_json; return $behaviors; }}
2. Use two columns in the user table to record the tolerance and timestamp information. To improve performance, consider using a cache or NoSQL to store this information.
Modify common/models/user.php, add red Tag code:
namespace Common\models;use yii;use yii\base\notsupportedexception;use yii\behaviors\timestampbehavior;use yii\db\ Activerecord;use yii\web\identityinterface;use yii\filters\ratelimitinterface;class User extends ActiveRecord Implements Identityinterface, ratelimitinterface{....//Returns the maximum number of requests allowed in a unit time, for example, [10, 60] indicates a maximum of 10 requests within 60 seconds. Public Function Getratelimit ($request, $action) {return [5, 10]; }//Returns the remaining number of allowed requests. Public Function Loadallowance ($request, $action) {return [$this->allowance, $this->allowance_updated_at]; }//The UNIX timestamp when the request was saved. Public Function Saveallowance ($request, $action, $allowance, $timestamp) {$this->allowance = $allowance; $this->allowance_updated_at = $timestamp; $this->save (); } ... public static function Findidentitybyaccesstoken ($token, $type = null) {//throw new Notsup Portedexception (' Findidentitybyaccesstoken ' is not implemented. '); FindidentThe implementation of the Itybyaccesstoken () method is system defined//For example, a simple scenario where each user has only one access token, which can store access tokens into the Access_token column of the user table, in the user class The simple implementation is as follows: Return Static::findone ([' access_token ' = $token]); } ....}
Recently read some information about the restful, self-made also wrote a restful instance, the following is the source
Catalogue Details:
restful/ request.php Data operation class response.php output class index.php Portal file . htaccess rewrite URL
Request.php: Contains a request class, which is a data manipulation class. After receiving the data for the URL, depending on how the URL is requested (get| Post| Put| patch| DELETE) The corresponding additions and deletions to the data, and return the results of the operation:
<?php/** * Data Operation class */class request{//allowed request mode private static $method _type = Array (' Get ', ' post ', ' Put ', ' Patch ', ' d Elete '); Test data private static $test _class = Array (1 = = Array (' name ' = ' Tofoban ', ' count ' = +), 2 = a Rray (' name ' = ' + ' IELTS class ', ' count ' = 20),); public static function Getrequest () {//Request mode $method = Strtolower ($_server[' Request_method ')); if (In_array ($method, Self:: $method _type)) {//Invoke the method corresponding to the request $data _name = $method. ' Data '; Return self:: $data _name ($_request); } return false; }//get gets the information private static function GetData ($request _data) {$class _id = (int) $request _data[' class '); GET/CLASS/ID: Get information on a given class if ($class _id > 0) {return self:: $test _class[$class _id]; } else {//get/class: Lists all classes return self:: $test _class; }}//post/class: Create a new class private static function PostData ($reQuest_data) {if (!empty ($request _data[' name ')) {$data [' name '] = $request _data[' name ']; $data [' count '] = (int) $request _data[' count ']; Self:: $test _class[] = $data; Return self:: $test _class;//Returns the newly generated resource object} else {return false; }}//PUT/CLASS/ID: Update information for a given class (all information) private static function PutData ($request _data) {$class _id = (int) $request _data[' class ']; if ($class _id = = 0) {return false; } $data = Array (); if (!empty ($request _data[' name ') && isset ($request _data[' count ')) {$data [' name '] = $request _data[' na Me ']; $data [' count '] = (int) $request _data[' count ']; Self:: $test _class[$class _id] = $data; Return self:: $test _class; } else {return false; }}//PATCH/CLASS/ID: Update information for a given class (some information) private static function Patchdata ($request _data) {$class _id = ( int) $request _dAta[' class ']; if ($class _id = = 0) {return false; } if (!empty ($request _data[' name ')) {self:: $test _class[$class _id][' name '] = $request _data[' name ']; } if (Isset ($request _data[' count ')) {self:: $test _class[$class _id][' count '] = (int) $request _data[' Count ']; } return Self:: $test _class; }//delete/class/id: Delete a class private static function DeleteData ($request _data) {$class _id = (int) $request _d Ata[' class ']; if ($class _id = = 0) {return false; } unset (self:: $test _class[$class _id]); Return self:: $test _class; }}
Response.php: Contains a request class, which is an output class. The array returned by the request class is stitched into the corresponding format according to the received Content-type, plus the header output
<?php/** * Output class */class response{const Http_version = "http/1.1"; Returns the result public static function Sendresponse ($data) {//Gets data if ($data) {$code = 200; $message = ' OK '; } else {$code = 404; $data = Array (' ERROR ' = ' not Found '); $message = ' not Found '; }//Output result header (self::http_version. " " . $code. " " . $message); $content _type = isset ($_server[' Content_Type ')? $_server[' content_type ': $_server[' http_accept ']; if (Strpos ($content _type, ' Application/json ')!== false) {header ("Content-type:application/json"); echo Self::encodejson ($data); } else if (Strpos ($content _type, ' Application/xml ')!== false) {header ("content-type:application/xml"); echo Self::encodexml ($data); } else {header ("content-type:text/html"); echo self::encodehtml ($data); }}//json format private static function Encodejson ($responseData) {return json_encode ($responseData); }//xml format private static function Encodexml ($responseData) {$xml = new SimpleXMLElement (' <?xml version = "1.0"?><rest></rest> '); foreach ($responseData as $key = + $value) {if (Is_array ($value)) {foreach ($value as $k =&G T $v) {$xml->addchild ($k, $v); }} else {$xml->addchild ($key, $value); }} return $xml->asxml (); }//html format private static function encodehtml ($responseData) {$html = "<table border= ' 1 ' >"; foreach ($responseData as $key = = $value) {$html. = "<tr>"; if (Is_array ($value)) {foreach ($value as $k = = $v) {$html. = "<td>". $k. " </td><td> ". $v. "</td>"; } }else {$html. = "<td>". $key. "</td><td>". $value. "</td>"; } $html. = "</tr>"; } $html. = "</table>"; return $html; }}
index.php: The import file, call the request class to get the data and give it to response processing, and finally return the result
<?php//data operation class require (' request.php ');//Output class require (' response.php ');//Get Data $data = Request::getrequest ();// Output result Response::sendresponse ($data);
Next: PHP implementation of RESTful style API example (iii)
Yii2 Framework RESTful API tutorial