You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
6.5 KiB
107 lines
6.5 KiB
10 years ago
|
バージョン管理
|
||
|
==============
|
||
|
|
||
|
良い API は*バージョン管理* されています。
|
||
|
一つのバージョンを絶え間なく変更するのではなく、変更と新機能は API の新しいバージョンとして実装されます。
|
||
|
クライアント側とサーバ側の両方を完全に制御できるウェブアプリケーションとは違って、API はあなたの制御が及ばないクライアントによって使用されることを意図したものです。
|
||
|
このため、API の後方互換性 (BC) は、可能な限り保たれなければなりません。
|
||
|
BC を損なうかも知れない変更が必要な場合は、それを API の新しいバージョンにおいて導入し、バージョン番号を上げるべきです。
|
||
|
そうすれば、既存のクライアントは、API の古いけれども動作するバージョンを使い続けることが出来ますし、新しいまたはアップグレードされたクライアントは、新しい API バージョンで新しい機能を使うことが出来ます。
|
||
|
|
||
|
> Tip|ヒント: API のバージョン番号の設計に関する詳細情報は [Semantic Versioning](http://semver.org/) を参照してください。
|
||
|
|
||
|
API のバージョン管理を実装する方法としてよく使われるのは、バージョン番号を API の URL に埋め込む方法です。
|
||
|
例えば、`http://example.com/v1/users` が API バージョン 1 の `/users` エンドポイントを指す、というものです。
|
||
|
|
||
|
API のバージョン管理のもう一つの方法は、最近流行しているものですが、バージョン番号を HTTP リクエストヘッダに付ける方法です。
|
||
|
これは、典型的には、`Accept` ヘッダによって行われます。
|
||
|
|
||
|
```
|
||
|
// パラメータによって
|
||
|
Accept: application/json; version=v1
|
||
|
// ベンダーのコンテントタイプによって
|
||
|
Accept: application/vnd.company.myapp-v1+json
|
||
|
```
|
||
|
|
||
|
どちらの方法にも長所と短所があり、それぞれのアプローチに対して多くの議論があります。
|
||
|
下記では、この二つの方法をミックスした API バージョン管理の実際的な戦略を紹介します。
|
||
|
|
||
|
* API 実装の各メジャーバージョンを独立したモジュールに置き、モジュールの ID はメジャーバージョン番号 (例えば `v1` や `v2`) とします。
|
||
|
当然ながら、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
|
||
|
```
|
||
|
|
||
|
アプリケーションの構成情報は次のようなものになります。
|
||
|
|
||
|
```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\filters\ContentNegotiator|contentNegotiator]] ビヘイビアによって提供されるコンテントネゴシエーションの機能を利用することが出来ます。
|
||
|
`contentNegotiator` ビヘイビアは、どのコンテントタイプをサポートするかを決定するときに、[[yii\web\Response::acceptParams]] プロパティをセットします。
|
||
|
|
||
|
例えば、リクエストが HTTP ヘッダ `Accept: application/json; version=v1` を伴って送信された場合、コンテントネゴシエーションの後では、[[yii\web\Response::acceptParams]] に `['version' => 'v1']` という値が含まれています。
|
||
|
|
||
|
`acceptParams` のバージョン情報に基づいて、アクション、リソースクラス、シリアライザなどの個所で条件付きのコードを書いて、適切な機能を提供することが出来ます。
|
||
|
|
||
|
マイナーバージョンは、定義上、後方互換性を保つことを要求するものですので、コードの中でバージョンチェックをする個所はそれほど多くないものと期待されます。
|
||
|
そうでない場合は、たいていは、新しいメジャーバージョンを作成する必要がある、ということです。
|