2 フォロワー

バージョン管理

優れたAPIはバージョン管理されています。変更や新機能は、単一のバージョンを継続的に変更する代わりに、新しいAPIバージョンで実装されます。クライアントサイドとサーバーサイドの両方のコードを完全に制御できるWebアプリケーションとは異なり、APIはあなたの制御外のクライアントによって使用されることを目的としています。このため、APIの後方互換性(BC)は可能な限り維持する必要があります。BCを破壊する可能性のある変更が必要な場合は、新しいAPIバージョンで導入し、バージョン番号を繰り上げます。既存のクライアントは古い動作中のAPIバージョンを引き続き使用でき、新規またはアップグレードされたクライアントは新しいAPIバージョンで新しい機能を利用できます。

ヒント:APIバージョン番号の設計の詳細については、セマンティックバージョン管理を参照してください。

APIのバージョン管理を実装する一般的な方法の1つは、API URLにバージョン番号を埋め込むことです。たとえば、https://example.com/v1/usersは、APIバージョン1の/usersエンドポイントを表します。

最近勢いを増しているAPIバージョン管理のもう1つの方法は、HTTPリクエストヘッダーにバージョン番号を配置することです。これは通常、Acceptヘッダーを使用して行われます。

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

どちらの方法にも長所と短所があり、それぞれの方法について多くの議論があります。以下では、これら2つの方法を組み合わせた、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で編集する !