版本控制
API 版本控制允許你更改不同客戶端之間的行為。 REST framework 提供了許多不同的版本控制方案。
版本控制由傳入的客戶端請求決定,可能基於請求 URL 或請求 header。
有幾種有效的方法來處理版本控制。非版本化的系統也可能是合適的,特別是如果你正在為超出控制範圍的多個客戶端的非常長期的系統進行工程設計。
使用 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
函式與版本控制方案相關聯。你需要確保將當前請求包含為關鍵字引數,如下所示。
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 的版本控制方案一起使用時,請確保將請求作為上下文包含在序列化類中。
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_version
,allowed_versions
和 version_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`))
]
複製程式碼
如果你只需要簡單的版本控制方案,那麼 URLPathVersioning
和 NamespaceVersioning
都是可以的。 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()
方法。有關示例,請參閱原始碼。