Building a RESTful API with Yii2

 

 

 

Presented by Damien Buttler

phpMelb - March 15, 2016

What is an API?

What's an API?

An API is an Application Programming Interface that is designed to allow other programs to interact with it.

To create/update/read/delete data through agnostic interface.

What is a RESTful API?

Representational State Transfer

REST is an architectural style consisting of a coordinated set of architectural constraints applied to components, connectors, and data elements, within a distributed hypermedia system.

Basic RESTful request Types

ActionMethodURL Example
Create recordPOSThttp://domain.com/user
Update recordPUThttp://domain.com/user/{id}
List recordsGEThttp://domain.com/user
View recordGEThttp://domain.com/user/{id}
Delete recordDELETEhttp://domain.com/user/{id}

Building the API with Yii2

Install Yii

                        
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer create-project --prefer-dist yiisoft/yii2-app-advanced yii-application
./init (and follow prompts)
                        
                    

Configure Database

Add file: common/config/db.php
                        
<?php

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=phpmelb',
    'username' => 'phpmelb',
    'password' => 'phpmelb',
    'charset' => 'utf8',
];
                        
                    
Include config for frontend: frontend/config/main.php and console/config/main.php

                        
'db' => require(__DIR__ .'/../../common/config/db.php'),
                        
                    
Run migration:

                        
./yii migrate
                        
                    
Run Gii to create model Class:
                        
./yii gii/model --tableName=user --modelClass=User
                        
                    
Move file from console/models to common/models and change namespace to:
                        
namespace common\models;
                        
                    
Configure Gii in frontend/config/main.php
                        
    'modules' => [
        'gii' => [
            'class' => 'yii\gii\Module',
            'allowedIPs' => ['192.168.10.1'],
        ],
    ],

                        
                    
And run gii from to create the User controller:
                        
http://phpmelb.api/index.php?r=gii
                        
                    

Configure application as a RESTful API

From guide: http://www.yiiframework.com/doc-2.0/guide-rest-quick-start.html

Edit frontend/controllers/UserController.php
                        
<?php

namespace frontend\controllers;

use yii\rest\ActiveController;

class UserController extends ActiveController
{
    public $modelClass = 'common\models\User';
}
                        
                    
Pretty Urls: Edit frontend/config/main.php
                        
'urlManager' => [
    'enablePrettyUrl' => true,
    'enableStrictParsing' => true,
    'showScriptName' => false,
    'rules' => [
        ['class' => 'yii\rest\UrlRule', 'controller' => 'user', 'pluralize' => false],
    ],
],
Allow Json input: Edit frontend/config/main.php
                        
'request' => [
    'parsers' => [
        'application/json' => 'yii\web\JsonParser',
    ]
],

User creation payload

POST: http://phpmelb.api/user/create
                        
{
    "username": "bob",
    "email": "bob@gmail.com",
    "password_hash":"mypassword"
}
                        

User View

View user and its attributes: GET http://phpmelb.api/user/1
                        
{
    "id": 1,
    "username": "bob",
    "email": "bob@gmail.com",
    "password_hash":"mypassword"
}
                        
Restrict field outputs. Add fields method to common/models/User.php
                        
public function fields()
{
    return [
        'id',
        'username',
        'email',
    ];
}
                        

Default API Response Headers

                        
X-Pagination-Current-Page => 1
X-Pagination-Page-Count => 1
X-Pagination-Per-Page => 20
X-Pagination-Total-Count => 2
                        

Refining result set

Limit results per page?per-page=3
Show specific page?page=2

Overriding actions and further refining of results

Edit frontend/controllers/UserController.php
                        
    public function actions()
    {
        $actions = parent::actions();
        $actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider'];

        return $actions;
    }

    public function prepareDataProvider()
    {
        $searchModel = new \common\models\UserSearch();
        return $searchModel->search(Yii::$app->request->queryParams);
    }

                        

Use Gii CRUD tool to generate User Search file

Modify load params method in common/models/UserSearch.php:
                        
$this->load($params, '');
                        
And filter by model attributes:
                        
?username=bob
                        
And filter by pseudo attributes:
                        
?time_from=2016-01-01 10:00:00&time_to=2016-01-31 23:59:59
->andFilterWhere(['between', 'created_at', $this->time_from, $this->time_to]);

Behaviours

Adding behaviours to the API. Behaviours is a way to allow Yii/PHP to work around the limitation that PHP can only extend one class.

Add CORS and Auth behaviours. CORS filter must be first.
                        
    public function behaviors()
    {
        return ArrayHelper::merge([
            'corsFilter' => [
                'class' => Cors::className(),
            ],
            [
                'class' => HttpBearerAuth::className(),
                'except' => ['options'],
            ],
        ], parent::behaviors());

        return $behaviors;
    }
                        

Adding User Auth

New methods need to be added to both the user controller and model. It would be easier to refer to the commit on Github

Adding behaviours to the base model

Add to common/models/BaseModel.php
                        
public function behaviors()
{
    return [
        [
            'class' => TimestampBehavior::className(),
            'createdAtAttribute' => 'created_at',
            'updatedAtAttribute' => 'updated_at',
            'value' => function() { return date('Y-m-d H:i:s'); },
        ],
        [
            'class' => BlameableBehavior::className(),
            'createdByAttribute' => 'created_by',
            'updatedByAttribute' => 'updated_by',
        ],
    ];
}

                        

Adding an Admin Backend

Adding a standard Yii web admin backend by running the the Gii CRUD tool to build the backend files.

Point browser to backend domain: eg. http://admin.domain.com/index.php?r=user

This user list page is automatically generated by Gii

This user update page is automatically generated by Gii

Building a RESTful API with Yii2

 

Presentation: https://doublehops.com/presentations/yii2-api-presentation/

VM and sample code: https://github.com/doublehops/yii-api-vm

 

Presented by Damien Buttler

phpMelb - March 15, 2016