VOOZH about

URL: https://dev.to/vikas_kambojindglobal/building-a-versioned-rest-api-with-authentication-in-yii2-advanced-566b

⇱ Building a Versioned REST API with Authentication in Yii2 Advanced - DEV Community


Yii2 Advanced comes with separate applications for frontend, backend, console, and shared code in common. It does not include an api application by default, but Yii2 Advanced is designed in a way that makes adding one straightforward.

In this post, we’ll create a separate API application, configure REST routes, add versioned URLs like /v1/users and /v2/users, and prepare the structure for authentication.

Yii2 Advanced Project Structure

A default Yii2 Advanced project usually looks like this:

backend/
common/
console/
frontend/
vendor/
composer.json

To build an API, create a new application folder at the same level as frontend and backend:

api/

After adding it, your structure becomes:

api/
backend/
common/
console/
frontend/
vendor/
composer.json

Creating the API Application

Inside the api folder, create this structure:

api/
 config/
 main.php
 main-local.php
 params.php
 controllers/
 modules/
 runtime/
 web/
 index.php

The api/web folder is the public document root for the API application.

Creating api/web/index.php

Create the entry file:

<?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';
require __DIR__ . '/../../common/config/bootstrap.php';

$config = yii\helpers\ArrayHelper::merge(
 require __DIR__ . '/../../common/config/main.php',
 require __DIR__ . '/../../common/config/main-local.php',
 require __DIR__ . '/../config/main.php',
 require __DIR__ . '/../config/main-local.php'
);

(new yii\web\Application($config))->run();

This bootstraps Yii and loads the shared common config plus API-specific configuration.

Creating api/config/main.php

Create the main API config file:

<?php

return [
 'id' => 'app-api',
 'basePath' => dirname(__DIR__),
 'controllerNamespace' => 'api\controllers',

 'components' => [
 'request' => [
 'csrfParam' => '_csrf-api',
 'parsers' => [
 'application/json' => yii\web\JsonParser::class,
 ],
 ],

 'response' => [
 'format' => yii\web\Response::FORMAT_JSON,
 ],

 'urlManager' => [
 'enablePrettyUrl' => true,
 'showScriptName' => false,
 'rules' => [
 'GET /' => 'site/index',
 ],
 ],
 ],
];

The important parts are:

'parsers' => [
 'application/json' => yii\web\JsonParser::class,
],

This allows Yii2 to read JSON request bodies.

And:

'response' => [
 'format' => yii\web\Response::FORMAT_JSON,
],

This makes API responses return JSON by default.

Creating api/config/main-local.php

Create a local config file:

<?php

return [
 'components' => [
 'request' => [
 'cookieValidationKey' => 'generate-a-random-secret-key-here',
 ],
 ],
];

Use a real random string for cookieValidationKey.

Creating api/config/params.php

Create an empty params file:

<?php

return [];

Adding Autoloading

If your project does not already autoload the api namespace, add it to composer.json:

"autoload":{"psr-4":{"api\\":"api/"}}

Then run:

composer dump-autoload

Creating a Test Controller

Create a simple controller to confirm the API app works.

<?php

namespace api\controllers;

use yii\rest\Controller;

class SiteController extends Controller
{
 public function actionIndex()
 {
 return [
 'status' => 'ok',
 'app' => 'api',
 ];
 }
}

With this URL rule:

'rules' => [
 'GET /' => 'site/index',
],

You should be able to open:

https://api.yourdomain.com/

or locally:

http://localhost:8080/

and see:

{"status":"ok","app":"api"}

Where Do URL Rules Go?

URL rules are added inside the urlManager component in api/config/main.php:

'components' => [
 'urlManager' => [
 'enablePrettyUrl' => true,
 'showScriptName' => false,
 'rules' => [
 'GET /' => 'site/index',
 ],
 ],
],

The rules array belongs inside:

components.urlManager

not at the top level of the config.

Do You Need to Add Every API Endpoint Manually?

No. Yii2 REST URL rules can generate standard REST endpoints automatically.

For example:

[
 'class' => yii\rest\UrlRule::class,
 'controller' => 'user',
]

generates standard REST routes like:

GET /users
GET /users/123
POST /users
PUT /users/123
PATCH /users/123
DELETE /users/123

Yii2 pluralizes REST controller names by default:

user -> /users
product -> /products
order -> /orders

For multiple controllers, you can group them:

[
 'class' => yii\rest\UrlRule::class,
 'controller' => [
 'user',
 'product',
 'order',
 'payment',
 'notification',
 ],
],

This gives each controller its standard REST URLs.

Adding Custom API Actions

For non-standard endpoints, use extraPatterns.

Example:

[
 'class' => yii\rest\UrlRule::class,
 'controller' => 'auth',
 'extraPatterns' => [
 'POST login' => 'login',
 'POST logout' => 'logout',
 'POST refresh-token' => 'refresh-token',
 ],
],

This creates:

POST /auth/login
POST /auth/logout
POST /auth/refresh-token

So even with many endpoints, you usually do not list all of them manually. You define REST controllers and add only custom routes where needed.

Complete URLs

The complete URL depends on your API base URL.

If your API is hosted at:

https://api.yourdomain.com

then the routes become:

GET https://api.yourdomain.com/users
GET https://api.yourdomain.com/users/123
POST https://api.yourdomain.com/users
PUT https://api.yourdomain.com/users/123
PATCH https://api.yourdomain.com/users/123
DELETE https://api.yourdomain.com/users/123

For custom auth routes:

POST https://api.yourdomain.com/auth/login
POST https://api.yourdomain.com/auth/logout
POST https://api.yourdomain.com/auth/refresh-token

If running locally:

http://localhost:8080/users
http://localhost:8080/auth/login

If pretty URLs are not configured correctly, URLs may include index.php:

http://localhost:8080/index.php/users
http://localhost:8080/index.php/auth/login

Adding API Versioning

For versioned API URLs like:

https://api.yourdomain.com/v1/users
https://api.yourdomain.com/v2/users

the recommended Yii2 approach is to use modules.

Create this structure:

api/
 modules/
 v1/
 Module.php
 controllers/
 UserController.php
 v2/
 Module.php
 controllers/
 UserController.php

Creating the V1 Module

Create api/modules/v1/Module.php:

<?php

namespace api\modules\v1;

class Module extends \yii\base\Module
{
 public $controllerNamespace = 'api\modules\v1\controllers';
}

Creating the V2 Module

Create api/modules/v2/Module.php:

<?php

namespace api\modules\v2;

class Module extends \yii\base\Module
{
 public $controllerNamespace = 'api\modules\v2\controllers';
}

Registering API Modules

Register the modules in api/config/main.php:

'modules' => [
 'v1' => [
 'class' => api\modules\v1\Module::class,
 ],
 'v2' => [
 'class' => api\modules\v2\Module::class,
 ],
],

Your config now includes the versioned modules.

Adding Versioned URL Rules

Inside components.urlManager.rules, add versioned REST rules:

'rules' => [
 [
 'class' => yii\rest\UrlRule::class,
 'controller' => [
 'v1/user',
 'v1/product',
 'v1/order',
 ],
 ],
 [
 'class' => yii\rest\UrlRule::class,
 'controller' => [
 'v2/user',
 'v2/product',
 'v2/order',
 ],
 ],
],

Now Yii2 maps these controllers:

api/modules/v1/controllers/UserController.php
api/modules/v2/controllers/UserController.php

to these URLs:

/v1/users
/v2/users

Creating a Versioned Controller

Create api/modules/v1/controllers/UserController.php:

<?php

namespace api\modules\v1\controllers;

use yii\rest\ActiveController;

class UserController extends ActiveController
{
 public $modelClass = 'common\models\User';
}

Now the following endpoints are available:

GET /v1/users
GET /v1/users/123
POST /v1/users
PUT /v1/users/123
PATCH /v1/users/123
DELETE /v1/users/123

For v2, create:

<?php

namespace api\modules\v2\controllers;

use yii\rest\ActiveController;

class UserController extends ActiveController
{
 public $modelClass = 'common\models\User';
}

Now v2 endpoints are available:

GET /v2/users
GET /v2/users/123
POST /v2/users
PUT /v2/users/123
PATCH /v2/users/123
DELETE /v2/users/123

Adding Versioned Auth Endpoints

For an auth controller inside v1:

[
 'class' => yii\rest\UrlRule::class,
 'controller' => 'v1/auth',
 'extraPatterns' => [
 'POST login' => 'login',
 'POST logout' => 'logout',
 'POST refresh-token' => 'refresh-token',
 ],
],

This creates:

POST /v1/auth/login
POST /v1/auth/logout
POST /v1/auth/refresh-token

Your controller would live at:

api/modules/v1/controllers/AuthController.php

Adding Bearer Token Authentication

Yii2 supports bearer token authentication with yii\filters\auth\HttpBearerAuth.

In a REST controller, add:

use yii\filters\auth\HttpBearerAuth;

public function behaviors()
{
 $behaviors = parent::behaviors();

 $behaviors['authenticator'] = [
 'class' => HttpBearerAuth::class,
 ];

 return $behaviors;
}

Example:

<?php

namespace api\modules\v1\controllers;

use yii\rest\ActiveController;
use yii\filters\auth\HttpBearerAuth;

class UserController extends ActiveController
{
 public $modelClass = 'common\models\User';

 public function behaviors()
 {
 $behaviors = parent::behaviors();

 $behaviors['authenticator'] = [
 'class' => HttpBearerAuth::class,
 ];

 return $behaviors;
 }
}

Requests must include an Authorization header:

Authorization: Bearer your-token-here

Finding Users by Access Token

Your common\models\User model should implement:

public static function findIdentityByAccessToken($token, $type = null)
{
 return static::findOne(['access_token' => $token]);
}

For this to work, your user table needs an access_token column, or you need a separate token table.

For production APIs, avoid storing permanent plain tokens. A better approach is usually:

short-lived access tokens
refresh tokens
hashed token storage
JWT
OAuth2

The simple access_token example is useful for learning, but production authentication should be designed more carefully.

Recommended Final Structure

A versioned API app may look like this:

api/
 config/
 main.php
 main-local.php
 params.php
 modules/
 v1/
 Module.php
 controllers/
 AuthController.php
 UserController.php
 ProductController.php
 v2/
 Module.php
 controllers/
 AuthController.php
 UserController.php
 ProductController.php
 runtime/
 web/
 index.php
backend/
common/
console/
frontend/

Final Notes

In Yii2 Advanced, an API is simply another application beside frontend and backend. You create the api folder manually, give it its own config and web entry point, then use REST URL rules and modules to keep the code organized.

The most common pattern is:

api/modules/v1/controllers/UserController.php -> /v1/users
api/modules/v2/controllers/UserController.php -> /v2/users

This keeps your API versions cleanly separated in both the URL and the codebase.