Yii 2.0 – Các bước xây dựng một REST API

Like
Like Love Haha Wow Sad Angry

This is wiki page is useful if you are trying to build a customized REST API in Yii2.0

Note: Yii 2 includes a generic REST feature (ActiveController class) that implements a basic REST API for one of your models that you may be able to easily use and not have to write all the below code. http://www.yiiframework.com/doc-2.0/guide-rest-quick-start.html

Github: https://github.com/sirinibin/yii2rest

Note:This example is based on the table: user(id(PK AI),name,age,createdAt,updatedAt)

1.Action index

Request:

[code lang="js"]
========
URL: api/user/index
method:GET
[/code]

Params:

[code lang="js"]
{
"page": 1,
"limit": 5,
"sort": "id",
"order": false,
"filter": {},
"dateFilter": {
"from": "2014-09-04",
"to": "2014-09-05"
}
}
[/code]

[code lang="js"]
Note1: "page"=>is the current page number
Note2: "limit"=>no.of records in a single page
Note3: "sort"=>sort field(ie this can be id,name,age createdAt or updatedAt)
Note4: "order"=>This can be true/false. true=>ascending order while false=>descending order
Note5: filter=>is a json object to pass any filter elements. eg:{name:'abc',age:20}
[/code]

Response:

[code lang="js"]
{
"status": 1,
"data": [
{
"id": 30,
"name": "john",
"age": 78,
"createdAt": "2014-09-05 01:53:31",
"updatedAt": "2014-09-05 01:53:51"
},
{
"id": 29,
"name": "ben",
"age": 23,
"createdAt": "2014-09-05 01:53:28",
"updatedAt": "2014-09-05 01:54:00"
},
{
"id": 28,
"name": "rahul",
"age": 72,
"createdAt": "2014-09-05 01:53:25",
"updatedAt": "2014-09-05 01:54:09"
},
{
"id": 27,
"name": "shafeeque",
"age": 76,
"createdAt": "2014-09-05 01:53:21",
"updatedAt": "2014-09-05 01:54:24"
},
{
"id": 26,
"name": "sirin",
"age": 73,
"createdAt": "2014-09-04 19:51:49",
"updatedAt": "2014-09-05 01:54:32"
}
],
"totalItems": "8"
}
[/code]

Action Source code:

[php]
public function actionIndex()
{

$params=$_REQUEST;
$filter=array();
$sort="";

$page=1;
$limit=10;

if(isset($params['page']))
$page=$params['page'];

if(isset($params['limit']))
$limit=$params['limit'];

$offset=$limit*($page-1);

/* Filter elements */
if(isset($params['filter']))
{
$filter=(array)json_decode($params['filter']);
}

if(isset($params['datefilter']))
{
$datefilter=(array)json_decode($params['datefilter']);
}

if(isset($params['sort']))
{
$sort=$params['sort'];
if(isset($params['order']))
{
if($params['order']=="false")
$sort.=" desc";
else
$sort.=" asc";

}
}
$query=new Query;
$query->offset($offset)
->limit($limit)
->from('user')
->andFilterWhere(['like', 'id', $filter['id']])
->andFilterWhere(['like', 'name', $filter['name']])
->andFilterWhere(['like', 'age', $filter['age']])
->orderBy($sort)
->select("id,name,age,createdAt,updatedAt");

if($datefilter['from'])
{
$query->andWhere("createdAt >= '".$datefilter['from']."' ");
}
if($datefilter['to'])
{
$query->andWhere("createdAt <= '".$datefilter['to']."'"); } $command = $query->createCommand();
$models = $command->queryAll();

$totalItems=$query->count();

$this->setHeader(200);

echo json_encode(array('status'=>1,'data'=>$models,'totalItems'=>$totalItems),JSON_PRETTY_PRINT);

}
/* Functions to set header with status code. eg: 200 OK ,400 Bad Request etc..*/
private function setHeader($status)
{

$status_header = 'HTTP/1.1 ' . $status . ' ' . $this->_getStatusCodeMessage($status);
$content_type="application/json; charset=utf-8";

header($status_header);
header('Content-type: ' . $content_type);
header('X-Powered-By: ' . "Nintriva ");
}
private function _getStatusCodeMessage($status)
{
$codes = Array(
200 => 'OK',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
500 => 'Internal Server Error',
501 => 'Not Implemented',
);
return (isset($codes[$status])) ? $codes[$status] : '';
}
[/php]

2.Action View

[code lang="js"]
Request:
URL: api/user/view/30
method:GET

Note1: "30"=>is the Pk of a record in the user table
[/code]

Response:

[code lang="js"]
{
"status": 1,
"data": {
"id": 30,
"name": "john",
"age": 78,
"createdAt": "2014-09-05 01:53:31",
"updatedAt": "2014-09-05 01:53:51"
}
}
[/code]

Action Source code:

[php]
public function actionView($id)
{

$model=$this->findModel($id);

$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>array_filter($model->attributes)),JSON_PRETTY_PRINT);

}
/* function to find the requested record/model */
protected function findModel($id)
{
if (($model = User::findOne($id)) !== null) {
return $model;
} else {

$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'message'=>'Bad request'),JSON_PRETTY_PRINT);
exit;
}
}
[/php]

3.Action Create

[code lang="js"]
Request:

URL: api/user/create
method:POST
[/code]

params:

[code lang="js"]
{
"name": "abc",
"age": 20
}
[/code]

Response:

[code lang="js"]
{
"status": 1,
"data": {
"id": 32,
"name": "abc",
"age": "20",
"createdAt": "2014-09-05 02:35:18",
"updatedAt": "2014-09-05 02:35:18"
}
}
[/code]

Action Source code:

[php]
public function actionCreate() {

$params=$_REQUEST;

$model = new User();
$model->attributes=$params;

if ($model->save()) {

$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>array_filter($model->attributes)),JSON_PRETTY_PRINT);

}
else
{
$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT);
}

}
[/php]

4.Action Update

Request:

[code lang="js"]
URL: api/user/update/32
Note1:"32"=>id(PK) of the record we are going to update
method: POST
[/code]

params:

[code lang="js"]
{
"name": "efg",
"age": 25
}
[/code]

Response:

[code lang="js"]
{
"status": 1,
"data": {
"id": 32,
"name": "efg",
"age": "25",
"createdAt": "2014-09-05 02:35:18",
"updatedAt": "2014-09-05 02:45:55"
}
}
[/code]

Action Source code:

[php]
public function actionUpdate($id)
{
$params=$_REQUEST;

$model = $this->findModel($id);

$model->attributes=$params;

if ($model->save()) {

$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>array_filter($model->attributes)),JSON_PRETTY_PRINT);

}
else
{
$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT);
}

}
[/php]

5.Action Delete

Request:

[code lang="js"]
URL: api/user/update/32
method:DELETE
Note1:"32"=>id(PK) of the record we are going to delete
[/code]

Response:

[code lang="js"]
{
"status": 1,
"data": {
"id": 32,
"name": "efg",
"age": 20,
"createdAt": "2014-09-05 02:40:44",
"updatedAt": "2014-09-05 02:40:44"
}
}
[/code]

Action Source code:

[php]
public function actionDelete($id)
{
$model=$this->findModel($id);

if($model->delete())
{
$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>array_filter($model->attributes)),JSON_PRETTY_PRINT);

}
else
{

$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT);
}

}
[/php]

6.Action DeleteAll

Used to delete multiple records at a time.

Request:

[code lang="js"]
URL: api/user/deleteall
method:POST
[/code]

params:

[code lang="js"]
{
"ids": "[27,28]"
}
Note1:"ids"=>a list of id(Pk)'s to be deleted
[/code]

Response:

[code lang="js"]
{
"status": 1,
"data": [
{
"id": 27,
"name": "shafeeque",
"age": 76,
"createdAt": "2014-09-05 01:53:21",
"updatedAt": "2014-09-05 01:54:24"
},
{
"id": 28,
"name": "rahul",
"age": 72,
"createdAt": "2014-09-05 01:53:25",
"updatedAt": "2014-09-05 01:54:09"
}
]
}
[/code]

Action Source code:

[php]
public function actionDeleteall()
{
$ids=json_decode($_REQUEST['ids']);

$data=array();

foreach($ids as $id)
{
$model=$this->findModel($id);

if($model->delete())
$data[]=array_filter($model->attributes);
else
{
$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT);
return;
}
}

$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>$data),JSON_PRETTY_PRINT);

}
[/php]

7. Behaviour to fileter action methods

[php]
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'index'=>['get'],
'view'=>['get'],
'create'=>['post'],
'update'=>['post'],
'delete' => ['delete'],
'deleteall'=>['post'],
],

]
];
}

/* This will execute before any action */
public function beforeAction($event)
{
$action = $event->id;
if (isset($this->actions[$action])) {
$verbs = $this->actions[$action];
} elseif (isset($this->actions['*'])) {
$verbs = $this->actions['*'];
} else {
return $event->isValid;
}
$verb = Yii::$app->getRequest()->getMethod();

$allowed = array_map('strtoupper', $verbs);

if (!in_array($verb, $allowed)) {

$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'message'=>'Method not allowed'),JSON_PRETTY_PRINT);
exit;

}

return true;
}
[/php]

Controller source code:UserController.php

[php]
namespace app\modules\api\controllers;

use Yii;
use app\models\User;
use yii\data\ActiveDataProvider;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\db\Query;

/**
* UserController implements the CRUD actions for User model.
*/
class UserController extends Controller
{

public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'index'=>['get'],
'view'=>['get'],
'create'=>['post'],
'update'=>['post'],
'delete' => ['delete'],
'deleteall'=>['post'],
],

]
];
}

public function beforeAction($event)
{
$action = $event->id;
if (isset($this->actions[$action])) {
$verbs = $this->actions[$action];
} elseif (isset($this->actions['*'])) {
$verbs = $this->actions['*'];
} else {
return $event->isValid;
}
$verb = Yii::$app->getRequest()->getMethod();

$allowed = array_map('strtoupper', $verbs);

if (!in_array($verb, $allowed)) {

$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'message'=>'Method not allowed'),JSON_PRETTY_PRINT);
exit;

}

return true;
}

/**
* Lists all User models.
* @return mixed
*/
public function actionIndex()
{

$params=$_REQUEST;
$filter=array();
$sort="";

$page=1;
$limit=10;

if(isset($params['page']))
$page=$params['page'];

if(isset($params['limit']))
$limit=$params['limit'];

$offset=$limit*($page-1);

/* Filter elements */
if(isset($params['filter']))
{
$filter=(array)json_decode($params['filter']);
}

if(isset($params['datefilter']))
{
$datefilter=(array)json_decode($params['datefilter']);
}

if(isset($params['sort']))
{
$sort=$params['sort'];
if(isset($params['order']))
{
if($params['order']=="false")
$sort.=" desc";
else
$sort.=" asc";

}
}

$query=new Query;
$query->offset($offset)
->limit($limit)
->from('user')
->andFilterWhere(['like', 'id', $filter['id']])
->andFilterWhere(['like', 'name', $filter['name']])
->andFilterWhere(['like', 'age', $filter['age']])
->orderBy($sort)
->select("id,name,age,createdAt,updatedAt");

if($datefilter['from'])
{
$query->andWhere("createdAt >= '".$datefilter['from']."' ");
}
if($datefilter['to'])
{
$query->andWhere("createdAt <= '".$datefilter['to']."'"); } $command = $query->createCommand();
$models = $command->queryAll();

$totalItems=$query->count();

$this->setHeader(200);

echo json_encode(array('status'=>1,'data'=>$models,'totalItems'=>$totalItems),JSON_PRETTY_PRINT);

}

/**
* Displays a single User model.
* @param integer $id
* @return mixed
*/
public function actionView($id)
{

$model=$this->findModel($id);

$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>array_filter($model->attributes)),JSON_PRETTY_PRINT);

}

/**
* Creates a new User model.
* @return json
*/
public function actionCreate()
{

$params=$_REQUEST;

$model = new User();
$model->attributes=$params;

if ($model->save()) {

$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>array_filter($model->attributes)),JSON_PRETTY_PRINT);

}
else
{
$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT);
}

}

/**
* Updates an existing User model.
* @param integer $id
* @return json
*/
public function actionUpdate($id)
{
$params=$_REQUEST;

$model = $this->findModel($id);

$model->attributes=$params;

if ($model->save()) {

$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>array_filter($model->attributes)),JSON_PRETTY_PRINT);

}
else
{
$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT);
}

}

/**
* Deletes an existing User model.
* @param integer $id
* @return json
*/
public function actionDelete($id)
{
$model=$this->findModel($id);

if($model->delete())
{
$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>array_filter($model->attributes)),JSON_PRETTY_PRINT);

}
else
{

$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT);
}

}
/**
* Deletes an existing multiple User models at a time.
* @return json
*/
public function actionDeleteall()
{
$ids=json_decode($_REQUEST['ids']);

$data=array();

foreach($ids as $id)
{
$model=$this->findModel($id);

if($model->delete())
$data[]=array_filter($model->attributes);
else
{
$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT);
return;
}
}

$this->setHeader(200);
echo json_encode(array('status'=>1,'data'=>$data),JSON_PRETTY_PRINT);

}

/**
* Finds the User model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* @param integer $id
* @return User the loaded model
*/
protected function findModel($id)
{
if (($model = User::findOne($id)) !== null) {
return $model;
} else {

$this->setHeader(400);
echo json_encode(array('status'=>0,'error_code'=>400,'message'=>'Bad request'),JSON_PRETTY_PRINT);
exit;
}
}

private function setHeader($status)
{

$status_header = 'HTTP/1.1 ' . $status . ' ' . $this->_getStatusCodeMessage($status);
$content_type="application/json; charset=utf-8";

header($status_header);
header('Content-type: ' . $content_type);
header('X-Powered-By: ' . "Nintriva <nintriva.com>");
}
private function _getStatusCodeMessage($status)
{
// these could be stored in a .ini file and loaded
// via parse_ini_file()... however, this will suffice
// for an example
$codes = Array(
200 => 'OK',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
500 => 'Internal Server Error',
501 => 'Not Implemented',
);
return (isset($codes[$status])) ? $codes[$status] : '';
}
}
[/php]

Happy coding..

Like
Like Love Haha Wow Sad Angry

Nếu thấy hay thì like, share và comment để cùng nhau học tập nhé !^^

Bài viết liên quan

Bài viết cùng chuyên mục

Leave a Reply

Your email address will not be published. Required fields are marked *