Django REST framework API 指南(18):版本控制

官方原文連接
本系列文章 github 地址
轉載請註明出處python

版本控制

API 版本控制容許你更改不一樣客戶端之間的行爲。 REST framework 提供了許多不一樣的版本控制方案。git

版本控制由傳入的客戶端請求決定,可能基於請求 URL 或請求 header。github

有幾種有效的方法來處理版本控制。非版本化的系統也多是合適的,特別是若是你正在爲超出控制範圍的多個客戶端的很是長期的系統進行工程設計。正則表達式

使用 REST framework 進行版本控制

當啓用 API 版本控制時, request.version 屬性將包含一個對應於傳入客戶端請求的版本的字符串。django

默認狀況下,版本控制未啓用,request.version 將始終返回 Nonejson

基於版本的變化行爲

如何改變 API 的行爲取決於你,但你可能一般須要的一個示例是在新版本中切換到不一樣的序列化樣式。例如:api

def get_serializer_class(self):
    if self.request.version == 'v1':
        return AccountSerializerVersion1
    return AccountSerializer
複製代碼

反向解析版本化 API 的 URL

REST framework 包含的 reverse 函數與版本控制方案相關聯。你須要確保將當前請求包含爲關鍵字參數,以下所示。bash

from rest_framework.reverse import reverse

reverse('bookings-list', request=request)
複製代碼

上述功能將應用適合請求版本的任何 URL 轉換。例如:服務器

  • 若是正在使用 NamespacedVersioning,而且 API 版本爲 'v1',則使用的 URL lookup 將爲 'v1:bookings-list',可能會解析爲像 http://example.org/v1/bookings/ 這樣的 URL。
  • 若是正在使用 QueryParameterVersioning,而且 API 版本爲 1.0,則返回的 URL 可能與 http://example.org/bookings/?version=1.0 相似

版本化的 API 和超連接序列化類

將超連接序列化樣式與基於 URL 的版本控制方案一塊兒使用時,請確保將請求做爲上下文包含在序列化類中。app

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 setting key 定義。

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
複製代碼

其餘版本設置

如下 settings key 也用於控制版本控制:

  • DEFAULT_VERSION. 當沒有版本信息存在時,用於 request.version 的值。默認爲 None
  • ALLOWED_VERSIONS. 若是設置,則此值將限制版本控制方案可能返回的版本集,若是提供的版本不在此集中,則會引起錯誤。請注意,用於 DEFAULT_VERSION 設置的值始終被認爲是 ALLOWED_VERSIONS 集的一部分(除非它是 None)。默認爲 None
  • VERSION_PARAM. 應該用於任何版本控制參數的字符串,例如媒體類型或 URL 查詢參數。默認爲 'version'

你還能夠經過定義本身的版本控制方案並使用 default_versionallowed_versionsversion_param 類變量,在每一個視圖或每一個視圖集的基礎上設置版本控制類以及這三個值。例如,若是你想使用 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 header 中媒體類型的一部分。該版本做爲媒體類型參數包含在內,它補充了主要媒體類型。

這是一個使用 accept header 版本風格的示例 HTTP 請求。

GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
複製代碼

在上面的示例請求中 request.version 屬性將返回字符串 '1.0'

基於 Accept header 的版本控制一般被認爲是最佳實踐,儘管其餘樣式可能更適合你的客戶端需求。

使用 accept header 和 vendor media type

嚴格地說,json media type 不能被指定爲包含附加參數。若是你正在構建精心指定的公共 API,則能夠考慮使用vendor media type。爲此,請將你的渲染器配置爲使用基於 JSON 的渲染器和自定義 media type:

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
複製代碼

你的 URL conf 必須包含一個與 'version' 關鍵字參數相匹配的模式,以便版本控制方案可使用此信息。

urlpatterns = [
    url(
        r'^(?P<version>(v1|v2))/bookings/$',
        bookings_list,
        name='bookings-list'
    ),
    url(
        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 肯定的。

在下面的例子中,咱們給出了一組視圖兩個不一樣的可能的 URL 前綴,每一個前綴在不一樣的命名空間下:

# bookings/urls.py
urlpatterns = [
    url(r'^$', bookings_list, name='bookings-list'),
    url(r'^(?P<pk>[0-9]+)/$', bookings_detail, name='bookings-detail')
]

# urls.py
urlpatterns = [
    url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),
    url(r'^v2/bookings/', include('bookings.urls', namespace='v2'))
]
複製代碼

若是你只須要簡單的版本控制方案,那麼 URLPathVersioningNamespaceVersioning 都是能夠的。 URLPathVersioning方法可能更適合於小型項目,NamespaceVersioning 可能更容易管理大型項目。

HostNameVersioning

hostname 版本控制方案要求客戶端將請求的版本指定爲 URL 中 hostname 的一部分。

例如,如下是對 http://v1.example.com/bookings/ URL 的 HTTP 請求:

GET /bookings/ HTTP/1.1
Host: v1.example.com
Accept: application/json 
複製代碼

默認狀況下,這個實現指望 hostname 匹配這個簡單的正則表達式:

^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$
複製代碼

請注意,第一組用括號括起來,表示這是 hostname 的匹配部分。

HostNameVersioning 方案在調試模式下可能會很笨拙,由於你一般會訪問諸如 127.0.0.1 的原始 IP 地址。

若是你有要求根據版本將傳入請求路由到不一樣的服務器,那麼基於 hostname 的版本控制就會特別有用,由於你能夠爲不一樣的 API 版本配置不一樣的 DNS 記錄。

QueryParameterVersioning

該方案是一種簡單的風格,其中包含版本做爲 URL 中的查詢參數。例如:

GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json 
複製代碼

自定義版本控制方案

要實現自定義版本控制方案,請繼承 BaseVersioning並覆蓋 .determine_version 方法。

舉個栗子

如下示例使用自定義的 X-API-Version header 來肯定所請求的版本。

class XAPIVersionScheme(versioning.BaseVersioning):
    def determine_version(self, request, *args, **kwargs):
        return request.META.get('HTTP_X_API_VERSION', None)
複製代碼

若是你的版本控制方案基於請求 URL,則還須要更改版本化 URL 的肯定方式。爲了作到這一點,你應該重寫類的 .reverse()方法。有關示例,請參閱源代碼。

相關文章
相關標籤/搜索