「复盘」Yii RESTful API 脚手架

安装 Yii 高级模板

Yii 安装文档

1
2
composer global require "fxp/composer-asset-plugin:^1.2.0"
composer create-project --prefer-dist yiisoft/yii2-app-advanced Yii2-RESTful-API-Scaffolding

初始化项目

在项目目录执行命令如下:

1
2
cd Yii2-RESTful-API-Scaffolding
php init

构建 RESTful API 项目目录

构建 RESTful API 项目目录,执行命令如下:

1
2
3
4
5
6
7
8
9
10
11
# 复制目录 frontend 为 api
cp -rf frontend api
# 复制目录 environments/dev/frontend 为 environments/dev/api
cp -rf environments/dev/frontend environments/dev/api
# 复制目录 environments/prod/frontend 为 environments/prod/api
cp -rf environments/prod/frontend environments/prod/api
# 给 api/runtime 和 api/web/assets 目录赋予读写权限
sudo chmod -R 777 api/runtime api/web/assets

接着将所有命名空间为 namespace frontend\ 替换为 namespace api\,将所有加载引用 use frontend\ 替换为 use api\

然后打开文件 common/config/bootstrap.php 并增删代码如下:

1
2
3
4
5
6
7
<?php
// 增加代码
Yii::setAlias('api', dirname(dirname(__DIR__)) . '/api');
// 删除代码
Yii::setAlias('@frontend', dirname(dirname(__DIR__)) . '/frontend');
Yii::setAlias('@backend', dirname(dirname(__DIR__)) . '/backend');

清理 RESTful API 项目,执行命令如下:

1
2
3
4
5
6
7
rm -rf backend
rm -rf frontend
rm -rf api/views
rm -rf api/assets
rm -rf api/web/css
rm -rf api/models/*
rm -rf api/controllers/SiteController.php

修改配置文件

打开文件 api/config/main.php,把文本 frontend 替换为 api,并添加配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
'components' => [
'request' => [
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'users' ,
'pluralize' => false
],
],
]
]

打开文件 common/config/main-local.php,添加配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
return [
'components' => [
...,
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=api',
'username' => 'root',
'password' => '123456',
'charset' => 'utf8',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '@common/mail',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => true,
],
],
];

访问域名

配置虚拟主机,并在本机 hosts 文件加入文本 127.0.0.1 yii2-restful-api-scaffolding.app。之后重启 Apache 并访问域名 yii2-restful-api-scaffolding.app/gii

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<VirtualHost *:80>
ServerName yii2-restful-api-scaffolding.app
DocumentRoot "/Users/LuisEdware/Git/Yii2-RESTful-API-Scaffolding/api/web/"
<Directory "/Users/LuisEdware/Git/Yii2-RESTful-API-Scaffolding/api/web/">
# use mod_rewrite for pretty URL support
RewriteEngine on
# If a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward the request to index.php
RewriteRule . index.php
# use index.php as index file
DirectoryIndex index.php
# ...other settings...
# Apache 2.4
Require all granted
## Apache 2.2
# Order allow,deny
# Allow from all
</Directory>
</VirtualHost>

新增数据库迁移文件

执行命令如下:

1
2
3
4
php yii migrate/create create_goods_table
php yii migrate/create insert_goods_table
php yii migrate/create create_goods_class_table
php yii migrate/create insert_goods_class_table

create_goods_table 迁移文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
use yii\db\Migration;
/**
* Handles the creation of table `goods`.
*/
class m170710_231631_create_goods_table extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('goods', [
'goodsId' => $this->primaryKey(),
'goodsName' => $this->string()->notNull(),
'goodsPrice' => $this->float()->notNull(),
'classId' => $this->integer()->notNull(),
]);
echo "m170710_231631_create_goods_table create table success.\n";
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('goods');
echo "m170710_231631_create_goods_table drop table success.\n";
}
}

create_goods_class_talbe 迁移文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
use yii\db\Migration;
/**
* Handles the creation of table `goods_class`.
*/
class m170711_011146_create_goods_class_table extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('goods_class', [
'goodsClassId' => $this->primaryKey(),
'goodsClassName' => $this->string()
]);
echo "m170711_011146_create_goods_class_table create table success.\n";
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('goods_class');
echo "m170711_011146_create_goods_class_table drop table success.\n";
}
}

insert_goods_table 迁移文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
use yii\db\Migration;
class m170711_011318_insert_data_to_goods_table extends Migration
{
public function up()
{
for ($i=1; $i < 6; $i++) {
$faker = Faker\Factory::create();
$this->insert('goods', [
'goodsId' => $i,
'goodsName' => $faker->name,
'goodsPrice' => $faker->randomFloat(2, 1, 1000),
'classId' => $i
]);
}
echo "m170711_011318_insert_data_to_goods_table insert data success.\n";
}
public function down()
{
$this->truncateTable('goods');
echo "m170711_011318_insert_data_to_goods_table cannot be reverted.\n";
}
}

insert_goods_class_talbe 迁移文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
use yii\db\Migration;
class m170711_011335_insert_data_to_goods_class_talbe extends Migration
{
public function up()
{
for ($i=1; $i < 6; $i++) {
$faker = Faker\Factory::create();
$this->insert('goods_class', [
'goodsClassId' => $i,
'goodsClassName' => $faker->name,
]);
}
echo "m170711_011335_insert_data_to_goods_class_talbe insert data success.\n";
}
public function down()
{
$this->truncateTable('goods_class');
echo "m170711_011335_insert_data_to_goods_class_talbe had remove all rows.\n";
}
}

接着在执行 php yii migrate,生成数据表并填充数据。

新增模块

打开域名 http://yii2-restful-api-scaffolding.app/gii/module,新增模块信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 给 api/modules 目录赋予读写权限
sudo chmod -R 777 api/modules
# Module Class
api\modules\v1\ApiModule
# Module ID
v1
# 勾选生成文件
modules/v1/ApiModule.php
# 在 api/config/main.php 配置文件加入配置项如下
'modules' => [
'v1' => [
'class' => 'api\modules\v1\ApiModule',
],
],

新增基础控制器

打开域名 http://yii2-restful-api-scaffolding.app/gii/controller,新增控制器信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 给 api/controllers 目录赋予读写权限
sudo chmod -R 777 api/controllers
# Controller Class
api\controllers\BaseController
# Action IDs
清空
# View Path
清空
# Base Class
yii\rest\ActiveController
# Code Template
默认

新增 api/modules/v1/controllers 目录,并新增控制器如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mkdir api/modules/v1/controllers
sudo chmod -R 777 api/modules/v1/controllers
# Controller Class,依次新增
api\modules\v1\controllers\GoodsController
api\modules\v1\controllers\GoodsClassController
# Action IDs
清空
# View Path
清空
# Base Class
yii\rest\ActiveController
# Code Template
默认

新增模型

打开域名 http://yii2-restful-api-scaffolding.app/gii/models,新增模型信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
# 给 api/models 赋予读写权限
sudo chmod -R 777 api/models
# Table Name
goods
goods_class
# Class Name
Goods
GoodsClass
# 其余选项默认

注册 ApiModule 启动引导

打开文件 api/config/main.php,在数组索引为 bootstrap 新增 v1 模块组件,修改文件 api/modules/v1/ApiModule.php 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
namespace api\modules\v1;
use yii\base\Module;
use yii\base\BootstrapInterface;
/**
* v1 module definition class
*/
class ApiModule extends Module implements BootstrapInterface
{
/**
* @inheritdoc
*/
public $controllerNamespace = 'api\modules\v1\controllers';
/**
* @inheritdoc
*/
public function init()
{
parent::init();
// custom initialization code goes here
}
public function bootstrap($app)
{
// 定义 RESTful API 路由
$app->getUrlManager()->addRules([
[
'class' => 'yii\rest\UrlRule',
'controller' => 'v1/goods'
],
[
'class' => 'yii\rest\UrlRule',
'controller' => 'v1/goods-class',
'extraPatterns' => [
'GET <id:\d+>/goods' => 'get-goods-by-goods-id'
]
],
]);
}
}

访问路由 http://yii2-restful-api-scaffolding.app/v1/goods 就可以看到接口返回数据

编写接口测试文档(一)

首先执行 composer require --prefer-dist light/yii2-swagger "~1.0.4" --dev,安装文档生成 Package。

然后使用 Gii 生成 swagger 模块组件

  • Module Class:api\modules\swagger\SwaggerModule
  • Module ID:swagger
  • Code File
    • modules/swagger/SwaggerModule.php
    • modules/swagger/controllers/DefaultController.php

然后在配置文件 api/config/main.php 的引导启动配置项加入 swagger 模块组件的 id 和模块组件配置

1
2
3
4
5
6
7
8
'modules' => [
'v1' => [
'class' => 'api\modules\v1\Module',
],
'swagger' => [
'class' => 'api\modules\swagger\SwaggerModule',
],
],

打开文件 api/modules/swagger/SwaggerModule.php,修改代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
namespace api\modules\swagger;
/**
* swagger module definition class
*/
class SwaggerModule extends \yii\base\Module implements \yii\base\BootstrapInterface
{
/**
* @inheritdoc
*/
public $controllerNamespace = 'api\modules\swagger\controllers';
/**
* @inheritdoc
*/
public function init()
{
parent::init();
// custom initialization code goes here
}
public function bootstrap($app)
{
// 定义路由
$app->getUrlManager()->addRules([
[
'class' => 'yii\web\UrlRule',
'pattern' => $this->id,
'route' => $this->id . '/default/doc',
],
[
'class' => 'yii\web\UrlRule',
'pattern' => $this->id . '/<action:\w+>',
'route' => $this->id . '/default/<action>',
],
]);
}
}

打开文件 api/modules/swagger/controllers/DefaultController.php,修改代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
namespace api\modules\swagger\controllers;
use Yii;
use yii\helpers\Url;
use yii\web\Controller;
/**
* Default controller for the `swagger` module
*/
class DefaultController extends Controller
{
public function actions()
{
return [
//文档预览地址
'doc' => [
'class' => 'light\swagger\SwaggerAction',
'restUrl' => Url::to(['api'], true),
],
//看到上面配置的*restUrl*了么,没错, 它就是指向这个地址
'api' => [
'class' => 'light\swagger\SwaggerApiAction',
//这里配置需要扫描的目录,不支持 yii 的 alias,所以需要这里直接获取到真实地址
'scanDir' => [
Yii::getAlias('@api/modules/v1/documents/'),
],
// 'api_key' => '',
],
];
}
}

新建目录 api/modules/v1/documents/controllers,新增文档注释文件 controllers/BaseControllerDocument.phpcontrollers/GoodsControllerDocument.php,代码如下:

BaseControllerDocument.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
/**
* @SWG\Swagger(
* swagger="2.0",
* @SWG\Info(
* title="Yii RESTful API(标题)",
* description="Yii RESTful API(描述)",
* termsOfService="七月十五九月初七",
* version="1.0.0(版本号)",
* @SWG\Contact(
* email="luisedware@gmail.com(邮件)",
* ),
* @SWG\License(
* name="MIT",
* url="http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
* ),
* ),
* host="yii2-restful-api-scaffolding.app/",
* basePath="v1/",
* schemes={"http"},
* produces={"application/json"},
* consumes={"application/json"},
* )
*/

GoodsControllerDocument.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
/**
* @SWG\Get(
* tags={"GoodsController「商品管理」"},
* path="/goods",
* summary="列出所有商品",
* operationId="index",
* description="列出所有商品",
* @SWG\Response(
* response=200,
* description="Successful Operation",
* )
* )
*/