How to configure versioning for Yii2 [Code Samples]
Updated 07 Mar 2023
4 Min
6173 Views
There is often a need to implement versioning of API functions for web and mobile applications. This need becomes a necessity to provide more flexible product support aimed to avoid system crash. I used to hear quite often about problems with using the same API across platforms. Frequently some platforms turn out to be ahead of others: for example, when you need to rewrite the half of the functionality on Android, iOS is still using old APIs. In my case it was necessary to use versioning for Yii2. Yii2 is installed via Composer and I will not describe the process of installation as there is a large amount of official documentation regarding it.
Yii2 directory structure for API
Below you can see the directory structure for API:
root_directory – project directory
Are you looking for Node.js framework? Read our research to learn How to Decide Between Express.js, Koa.js or Sails.js
It also contains Module.php – the main module file (entry point). We have options what name to choose and what path to set: it can be done in config/main.php.
- api/- assets/- config/- bootstrap.php- main.php- params.php- routes.php- modules/- v1/- controllers/- Controller.php- Module.php- v2/- controllers/- Controller.php- Module.php- runtime/- web/- index.php
Configuration and main files description for API working
We will have to set configurations for Yii2 to launch the app. Below you can see the description:
bootstrap.php
We set the alias for the needed directory paths.
<?php
Yii::setAlias('common', dirname(__DIR__));
Yii::setAlias('frontend', dirname(dirname(__DIR__)) . '/frontend');
Yii::setAlias('backend', dirname(dirname(__DIR__)) . '/backend');
Yii::setAlias('console', dirname(dirname(__DIR__)) . '/console');
Yii::setAlias('api', dirname(dirname(__DIR__)) . '/api');
params.php
We set parameters that the app needs:
<?php
return []
routes.php
This is our application routing. Here you can see two versions of get requests where:
v1, v2 – API versions;
URL will look like test_application/api/v1/some/test or test_application/api/v1/some/test, depending on what version we need.
<?php
return array(
'GET /v1/some/test/' => 'v1/some/test',
'GET /v2/some/test/' => 'v2/some/test',
);
main.php
It is the main configuration file. It loads the other. Here you can see the declaration what modules to use. In main.php GII code generator and logging are declared, the rules of routing through urlManager are set. Parsing for JSON requests is allowed.
<?php
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/params.php')
);
return [
'id' => 'test_application',
'basePath' => dirname(__DIR__) . '/..',
'bootstrap' => [
'log',
'gii',
'debug'
],
'modules' => [
'debug' => [
'class' => 'yii\debug\Module',
],
'v1' => [
'class' => 'app\api\modules\v1\Module',
],
'v2' => [
'class' => 'app\api\modules\v2\Module',
],
'gii' => 'yii\gii\Module',
],
'components' => [
'request' => [
// Enable JSON Input:
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
'enableCookieValidation' => true,
'enableCsrfValidation' => true,
'cookieValidationKey' => 'suiseiseki'
],
'user' => [
'identityClass' => 'app\common\models\User',
'enableAutoLogin' => true,
'enableSession' => false,
],
'log' => [
'traceLevel' => Yii_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
'logFile' => '@app/runtime/logs/error.log',
'maxFileSize' => 1024 * 2,
'maxLogFiles' => 20,
],
[
'class' => 'yii\log\FileTarget',
'levels' => ['info'],
'categories' => ['businesses'],
'logFile' => '@app/runtime/logs/api_calls_business.log',
'maxFileSize' => 1024 * 2,
'maxLogFiles' => 20,
],
[
'class' => 'yii\log\FileTarget',
'levels' => ['info'],
'categories' => ['customers'],
'logFile' => '@app/runtime/logs/api_calls_customer.log',
'maxFileSize' => 1024 * 2,
'maxLogFiles' => 50,
],
[
'class' => 'yii\log\FileTarget',
'levels' => ['info'],
'categories' => ['cardspring'],
'logFile' => '@app/runtime/logs/cardspring.log',
'maxFileSize' => 1024 * 2,
'maxLogFiles' => 50,
],
],
],
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => include('routes.php')
],
],
'params' => $params,
'aliases' => [
'@api' => '/path_to_project_directory/api'
],
];
Description of the main files
Entry point
Entry point is the main file of our application. The server starts Entry point first, then our application is launched.
index.php
<?php
defined('Yii_DEBUG') or define('Yii_DEBUG', true);
defined('Yii_ENV') or define('Yii_ENV', 'dev');
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
// Use a distinct configuration for the API
$config = require(__DIR__ . '/config/main.php');
(new yii\web\Application($config))->run();
The main file over the module
We inherit it from the basic module, which Yii2 provides.
Module – is sub-application, where you can organise your structure.
Cannot decide between front-end frameworks? Read our React vs Angular Research
$controllerNamespace – namespace for all the controllers in a module. It can also be declared in the configuration file.
Module.php
<?php
namespace app\api\modules\v1;
class Module extends \yii\base\Module
{
public $controllerNamespace = 'app\api\modules\v1\controllers';
public function init()
{
parent::init();
}
}
Here is the main controller, all the other are inherited.
Controller.php
<?php
namespace app\api\modules\v1\controllers;
class Controller extends \yii\rest\Controller
{
}
A controller, which will contain the API functions, in this case – test:
SomeController.php
<?php
namespace app\api\modules\v1\controllers;
class UserController extends Controller
{
public function actionTest()
{
}
}
NGINX configuration
As a server, I chose nginx in conjunction with PHP-FPM as I find it simple to set up and uses less memory than the apache2. Here is the code of nginx configuration:
Using the error_log and rewrite_log we install nginx logging in case of problems with the server.
We set the size of the request body using client_max_body_size.
We set up the UTF-8 unicode.
server {
listen 80;
server_name test_application;
root /path_to_project_directory/;
index index.php;
error_log /var/log/nginx/error_debug.log debug;
rewrite_log on;
charset utf-8;
client_max_body_size 100M;
location /api/v2/ {
autoindex on;
dav_methods PUT DELETE;
create_full_put_path on;
dav_access group:rw all:r;
rewrite ^/api/v2/(.*)?(.*)$ /api/index.php?$2;
alias /path_to_root_directory/api/;
index index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
location /api/v1/ {
autoindex on;
dav_methods PUT DELETE;
create_full_put_path on;
dav_access group:rw all:r;
rewrite ^/api/v1/(.*)?(.*)$ /api/index.php?$2;
alias /path_to_project_directory/api/;
index index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
}
}
location /api/ {
autoindex on;
dav_methods PUT DELETE;
create_full_put_path on;
dav_access group:rw all:r;
rewrite ^/api/gii?(.*)$ /api/index.php?$2;
alias /path_to_project_directory/api/;
index index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
}
Description of the main NGINX directives we use:
rewrite – changes the url request using regular expressions
alias – the directory, from which you will take an index file
Index – the index file. You can specify more than one, then they will be checked in the listed order
location – sets the configuration depending on the request URL
fastcgi_pass – sets address of FASTCGI-server. You can set php-fpm to work through sockets or connect on port 9000. It's all set in the php-fpm configuration file
dav_methods – lets you use the PUT and DELETE methods
create_full_put_path – allows you to create files only in the existing directory
dav_access group – set the rights for newly created files and directories
Conclusion
This example should allow to set up versioning fast. I have looked through tons of information and articles, but there was no ready example of setting or intelligible description for Yii2. That’s why I decided to write an article in the hope that it will help to save time for those who want to raise the project.
Evgeniy Altynpara is a CTO and member of the Forbes Councils’ community of tech professionals. He is an expert in software development and technological entrepreneurship and has 10+years of experience in digital transformation consulting in Healthcare, FinTech, Supply Chain and Logistics
Give us your impressions about this article
Give us your impressions about this article