バージョニング
インターフェースのバージョニングとは、デプロイされたクライアントを「丁寧に」停止させる方法に過ぎません。
— Roy Fielding.
APIバージョニングを使用すると、異なるクライアント間で動作を変更できます。REST frameworkは、さまざまなバージョニングスキームを提供します。
バージョニングは、着信クライアントリクエストによって決定され、リクエストURLまたはリクエストヘッダーに基づいて行われます。
バージョニングへのアプローチには、多くの有効な方法があります。バージョン管理されていないシステムも適切な場合があります。特に、制御できない複数のクライアントを持つ非常に長期的なシステムを設計している場合です。
REST frameworkでのバージョニング
APIバージョニングが有効になっている場合、request.version
属性には、着信クライアントリクエストで要求されたバージョンに対応する文字列が含まれます。
デフォルトでは、バージョニングは有効になっておらず、request.version
は常にNone
を返します。
バージョンに基づいて動作を変更する
APIの動作をどのように変更するかはあなた次第ですが、一般的に必要となる例としては、新しいバージョンで異なるシリアライゼーションスタイルに切り替えることが挙げられます。例えば
def get_serializer_class(self):
if self.request.version == 'v1':
return AccountSerializerVersion1
return AccountSerializer
バージョン管理されたAPIのURLを逆引きする
REST frameworkに含まれるreverse
関数は、バージョニングスキームと連携しています。次のように、現在のrequest
をキーワード引数として含める必要があります。
from rest_framework.reverse import reverse
reverse('bookings-list', request=request)
上記の関数は、リクエストバージョンに適したURL変換を適用します。例えば
NamespaceVersioning
が使用されていて、APIバージョンが「v1」の場合、使用されるURLルックアップは'v1:bookings-list'
となり、http://example.org/v1/bookings/
のようなURLに解決される可能性があります。QueryParameterVersioning
が使用されていて、APIバージョンが1.0
の場合、返されるURLはhttp://example.org/bookings/?version=1.0
のようになります。
バージョン管理されたAPIとハイパーリンクシリアライザー
ハイパーリンクシリアライゼーションスタイルとURLベースのバージョニングスキームを一緒に使用する場合は、リクエストをシリアライザーのコンテキストとして含めるようにしてください。
def get(self, request):
queryset = Booking.objects.all()
serializer = BookingsSerializer(queryset, many=True, context={'request': request})
return Response({'all_bookings': serializer.data})
そうすることで、返されるURLに適切なバージョニングを含めることができます。
バージョニングスキームの設定
バージョニングスキームは、DEFAULT_VERSIONING_CLASS
設定キーによって定義されます。
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'
}
明示的に設定されていない限り、DEFAULT_VERSIONING_CLASS
の値はNone
になります。この場合、request.version
属性は常にNone
を返します。
個々のビューでバージョニングスキームを設定することもできます。通常、グローバルに単一のバージョン管理スキームを使用する方が理にかなっているため、これは必要ありません。必要な場合は、versioning_class
属性を使用します。
class ProfileList(APIView):
versioning_class = versioning.QueryParameterVersioning
その他のバージョニング設定
以下の設定キーもバージョニングの制御に使用されます
DEFAULT_VERSION
。バージョニング情報が存在しない場合にrequest.version
に使用される値。デフォルトはNone
です。ALLOWED_VERSIONS
。設定されている場合、この値はバージョニングスキームによって返されるバージョンのセットを制限し、指定されたバージョンがこのセットにない場合はエラーを発生させます。DEFAULT_VERSION
設定に使用される値は、常にALLOWED_VERSIONS
セットの一部と見なされることに注意してください(None
でない限り)。デフォルトはNone
です。VERSION_PARAM
。メディアタイプまたはURLクエリパラメータなどのバージョニングパラメータに使用される文字列。デフォルトは'version'
です。
独自のバージョン管理スキームを定義し、`default_version`、`allowed_versions`、`version_param`クラス変数を使用することで、ビューごと、またはビューセットごとにバージョン管理クラスとこれら3つの値を設定することもできます。たとえば、`URLPathVersioning`を使用する場合
from rest_framework.versioning import URLPathVersioning
from rest_framework.views import APIView
class ExampleVersioning(URLPathVersioning):
default_version = ...
allowed_versions = ...
version_param = ...
class ExampleView(APIVIew):
versioning_class = ExampleVersioning
APIリファレンス
AcceptHeaderVersioning
このスキームでは、クライアントは`Accept`ヘッダーのメディアタイプの一部としてバージョンを指定する必要があります。バージョンは、メインのメディアタイプを補足するメディアタイプパラメータとして含まれています。
acceptヘッダーバージョニングスタイルを使用したHTTPリクエストの例を次に示します。
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
上記の例のリクエストでは、`request.version`属性は文字列`'1.0'`を返します。
アクセプトヘッダーに基づくバージョニングは、一般的に ベストプラクティスと見なされていますが、クライアントの要件によっては他のスタイルが適している場合があります。
ベンダーメディアタイプでアクセプトヘッダーを使用する
厳密に言えば、`json`メディアタイプは追加パラメータを含むとは指定されていません。適切に指定されたパブリックAPIを構築している場合は、ベンダーメディアタイプの使用を検討することができます。そのためには、レンダラーをカスタムメディアタイプを持つJSONベースのレンダラーを使用するように設定します
class BookingsAPIRenderer(JSONRenderer):
media_type = 'application/vnd.megacorp.bookings+json'
クライアントリクエストは次のようになります
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/vnd.megacorp.bookings+json; version=1.0
URLPathVersioning
このスキームでは、クライアントはURLパスの一部としてバージョンを指定する必要があります。
GET /v1/bookings/ HTTP/1.1
Host: example.com
Accept: application/json
URLconfには、バージョンと一致する`'version'`キーワード引数を持つパターンを含める必要があります。これにより、この情報がバージョニングスキームで使用できるようになります。
urlpatterns = [
re_path(
r'^(?P<version>(v1|v2))/bookings/$',
bookings_list,
name='bookings-list'
),
re_path(
r'^(?P<version>(v1|v2))/bookings/(?P<pk>[0-9]+)/$',
bookings_detail,
name='bookings-detail'
)
]
NamespaceVersioning
クライアントにとって、このスキームは`URLPathVersioning`と同じです。唯一の違いは、Djangoアプリケーションでの設定方法です。URLキーワード引数の代わりにURL名前空間を使用します。
GET /v1/something/ HTTP/1.1
Host: example.com
Accept: application/json
このスキームでは、`request.version`属性は、着信リクエストパスと一致する`namespace`に基づいて決定されます。
次の例では、ビューのセットに2つの異なるURLプレフィックスを指定しています。それぞれ異なる名前空間の下にあります
# bookings/urls.py
urlpatterns = [
re_path(r'^$', bookings_list, name='bookings-list'),
re_path(r'^(?P<pk>[0-9]+)/$', bookings_detail, name='bookings-detail')
]
# urls.py
urlpatterns = [
re_path(r'^v1/bookings/', include('bookings.urls', namespace='v1')),
re_path(r'^v2/bookings/', include('bookings.urls', namespace='v2'))
]
`URLPathVersioning`と`NamespaceVersioning`はどちらも、単純なバージョニングスキームが必要な場合に合理的です。 `URLPathVersioning`アプローチは、小規模なアドホックプロジェクトに適している可能性があり、`NamespaceVersioning`は大規模プロジェクトの管理が容易になる可能性があります。
HostNameVersioning
ホスト名バージョニングスキームでは、クライアントはURLのホスト名の一部として要求されたバージョンを指定する必要があります。
たとえば、`http://v1.example.com/bookings/` URLへのHTTPリクエストは次のとおりです
GET /bookings/ HTTP/1.1
Host: v1.example.com
Accept: application/json
デフォルトでは、この実装ではホスト名が次の単純な正規表現と一致することを想定しています
^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$
最初のグループは括弧で囲まれており、これがホスト名の一致部分であることを示していることに注意してください。
`HostNameVersioning`スキームは、`127.0.0.1`などの生のIPアドレスにアクセスすることが多いため、デバッグモードで使用するのが難しい場合があります。 カスタムサブドメインでlocalhostにアクセスする方法に関するさまざまなオンライントutorialがあり、この場合に役立つ場合があります。
ホスト名に基づくバージョニングは、バージョンに基づいて着信リクエストを異なるサーバーにルーティングする必要がある場合に特に役立ちます。異なるAPIバージョンに対して異なるDNSレコードを設定できるためです。
QueryParameterVersioning
このスキームは、URLのクエリパラメータとしてバージョンを含むシンプルなスタイルです。例えば
GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
カスタムバージョニングスキーム
カスタムバージョニングスキームを実装するには、`BaseVersioning`をサブクラス化し、`.determine_version`メソッドをオーバーライドします。
例
次の例では、カスタム`X-API-Version`ヘッダーを使用して、要求されたバージョンを決定します。
class XAPIVersionScheme(versioning.BaseVersioning):
def determine_version(self, request, *args, **kwargs):
return request.META.get('HTTP_X_API_VERSION', None)
バージョニングスキームがリクエストURLに基づいている場合は、バージョン付きURLの決定方法も変更する必要があります。そのためには、クラスの`.reverse()`メソッドをオーバーライドする必要があります。例については、ソースコードを参照してください。