版本化

未匹配的标注

版本化

一个优秀的 API 应该是支持 版本化的,即更改和新特性在新版本的 API 中实现,而不是不断地在同一个版本上修改。

与 Web 应用程序不同,您可以完全控制客户端和服务器端代码,API 意味着由超出您控制范围的客户端使用。出于这个原因,应该尽可能维护 API 的向后兼容性(BC)。如果有必要进行可能破坏 BC 的更改,则应该在 API 的新版本中引入它,并提高版本号。现有的客户端可以继续使用旧的、可用的 API 版本,新的或升级的客户端可以获得新 API 版本中的新功能。

小贴士:有关设计 API 版本号的更多信息,请参阅 语义化版本

常用方法

实现 API 版本控制的一种常见方法是将版本号嵌入到 API 的 URL 中。例如:http://example.com/v1/users 表示 API 版本 1 的 /users 端点(endpoint)。

API 版本控制的另一种方法是将版本号放在 HTTP 请求头中,这种方法最近得到了发展。这通常是通过 Accept 头文件完成的,例如:

// 通过一个参数
Accept: application/json; version=v1
// 通过供应商内容类型
Accept: application/vnd.company.myapp-v1+json

这两种方法都有各自的优点和缺点,对于每种方法都有很多争论。下面您将看到一种实用的 API 版本控制策略,它混合了这两种方法:

  • 将 API 实现的每个主要版本放在一个单独的模块中,其 ID 为主要版本号(例如:v1v2等) ,自然地,API 的 URL 中将包含主要的版本号。
  • 在每个主版本中(以及相应的模块中),使用 Accept HTTP 请求头来确定次要版本号,并相应地编写条件代码来响应次要版本。

版本化模块

对于服务于主版本的每个模块来说,它应该包含服务于该特定版本的资源和控制器类。为了更好地分离代码责任,您可以保留一组通用的基础资源和控制器类,并在每个单独的版本模块中对它们进行子类化。在子类中,实现具体的代码,如覆盖 Model::fields()

创建版本化模块

我们可以通过 Gii 的 module 构造器来实现基本的目录结构,记得取消控制器和视图创建,具体如图:

Gii 创建版本化模块

或者通过命令行:

php yii gii/module --moduleID=v1 --moduleClass='api\modules\v1\V1Module'

然后自行删除创建的 DefaultController 和 views 目录。然后在应用配置中,这样写:

......
    'modules' => [
        'v1' => [
            'class' => 'api\modules\v1\V1Module',
        ],
    ],

创建控制器

然后查看 api\modules\v1 目录下,如果没有一个 controllers 目录,那就新建一个,用来放控制器。你可以使用命令行来创建一个 rest 控制器,示例如下:

php yii gii/controller --controllerClass='api\modules\v1\controllers\UserController' --baseClass='yii\rest\ActiveController' --cations=

你也可以用 gii 来创建控制器,示例如下:

Gii 创建 rest 控制器

创建表

如果你还没有创建 user 表,没有关系,我们的 Yii 的高级应用模板,自带了示例的 user 表的迁移文件,你可以执行控制台命令,快速创建 user 表,具体如下:

php yii migrate/up

如图所示,这样就创建了 user 表:

数据库迁移创建表

创建模型

有了 user 表之后,我们在 api\modules\v1\models 目录下存放模型,当然你也可以放在其他或者公共的目录,你可以使用命令行来创建一个模型,示例如下:

php yii gii/model --tableName='demo_user' --ns='api\modules\v1\models' --modelClass='User' --generateLabelsFromComments=1 --useTablePrefix=1

你也可以用 gii 来创建模型,示例如下:

Gii 创建 rest 模型

然后在之前创建的 api\modules\v1\controllers\UserController 中,增加一句,示例如下:

namespace api\modules\v1\controllers;

class UserController extends \yii\rest\ActiveController
{
    public $modelClass = 'api\modules\v1\models\User';
}

目录结构

经过控制器和模型的创建,您的项目目录,示例如下:

api/
    common/
        controllers/
            UserController.php
            PostController.php
        models/
            User.php
            Post.php
    modules/
        v1/
            controllers/
                UserController.php
                PostController.php
            models/
                User.php
                Post.php
            V1Module.php
        v2/
            controllers/
                UserController.php
                PostController.php
            models/
                User.php
                Post.php
            V2Module.php

应用程序配置

您的应用程序配置如下所示:

return [
    'modules' => [
        'v1' => [
            'class' => 'app\modules\v1\Module',
        ],
        'v2' => [
            'class' => 'app\modules\v2\Module',
        ],
    ],
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,
            'enableStrictParsing' => true,
            'showScriptName' => false,
            'rules' => [
                ['class' => 'yii\rest\UrlRule', 'controller' => ['v1/user', 'v1/post']],
                ['class' => 'yii\rest\UrlRule', 'controller' => ['v2/user', 'v2/post']],
            ],
        ],
    ],
];

综上所述,http://example.com/v1/users 将返回版本 1 中的用户列表,而 http://example.com/v2/users 将返回版本 2 的用户。

不同主要版本的代码可以很好地隔离,都归功于 Yii 的 模块(modules)。但是,模块仍然可以通过公共基类及其他共享资源,实现跨模块代码重用。

次要版本号

要处理次要版本号,可以利用内容协商特性,它由 yii\filters\ContentNegotiator 内容协商行为来提供。当决定支持哪种内容类型时,该行为会设置 yii\web\Response::acceptParams 属性。

例如,如果一个请求被发送带有 HTTP 报头 Accept: application/json; version=v1,经过内容协商后,yii\web\Response::acceptParams 将包含值 ['version' => 'v1']

根据 acceptParams 中的版本信息,你可以在动作、资源类、序列化器等地方编写条件代码,以此来提供适当的功能。

由于次要版本的定义要求维护向后兼容性,所以,希望在代码中不会有太多的版本验证。否则,您可能需要创建一个新的主版本。

💖喜欢本文档的,欢迎点赞、收藏、留言或转发,谢谢支持!
作者邮箱:zhuzixian520@126.com,github地址:github.com/zhuzixian520

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
zhuzixian520
讨论数量: 0
发起讨论 只看当前版本


暂无话题~