2 位关注者

版本控制

一个良好的 API 是版本化的:更改和新功能在 API 的新版本中实现,而不是不断修改一个版本。与 Web 应用程序不同,您对客户端和服务器端代码都有完全控制权,API 旨在供您无法控制的客户端使用。因此,应尽可能维护 API 的向后兼容性 (BC)。如果需要进行可能破坏 BC 的更改,则应在新版本的 API 中引入它,并增加版本号。现有客户端可以继续使用旧版本的 API;新客户端或已升级的客户端可以在新版本的 API 中获得新功能。

提示:有关设计 API 版本号的更多信息,请参阅语义版本控制

实现 API 版本控制的一种常见方法是在 API URL 中嵌入版本号。例如,https://example.com/v1/users 代表 API 版本 1 的 /users 端点。

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

// via a parameter
Accept: application/json; version=v1
// via a vendor content type
Accept: application/vnd.company.myapp-v1+json

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

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

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

您的代码可能按以下方式组织

api/
    common/
        controllers/
            UserController.php
            PostController.php
        models/
            User.php
            Post.php
    modules/
        v1/
            controllers/
                UserController.php
                PostController.php
            models/
                User.php
                Post.php
            Module.php
        v2/
            controllers/
                UserController.php
                PostController.php
            models/
                User.php
                Post.php
            Module.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']],
            ],
        ],
    ],
];

根据以上代码,https://example.com/v1/users 将返回版本 1 中的用户列表,而 https://example.com/v2/users 将返回版本 2 的用户。

由于使用了模块,不同主要版本的代码可以很好地隔离。但是,模块仍然可以通过通用的基类和其他共享资源在模块之间重用代码。

为了处理次要版本号,您可以利用 contentNegotiator 行为提供的内容协商功能。contentNegotiator 行为将在确定支持哪种内容类型时设置 yii\web\Response::$acceptParams 属性。

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

根据acceptParams中的版本信息,您可以在操作、资源类、序列化器等地方编写条件代码,以提供相应的的功能。

由于次要版本根据定义需要保持向后兼容性,因此希望您的代码中不会有太多版本检查。否则,您可能需要创建新的主要版本。

发现错别字或您认为此页面需要改进?
在github上编辑它 !