對接口進行版本控制只是一種殺死已部署客戶端的“禮貌”方式?!?nbsp;Roy Fielding.
API 版本控制允許你在不同的客戶端之間更改行為. REST framework 提供了許多不同的版本控制方案。
版本控制由傳入的客戶端請求決定,可以基于請求的URL,也可以基于請求頭。
有許多有效的方法可以進行版本控制。無版本控制的系統(tǒng)也可能是合適的,特別是如果你正在為一個長期系統(tǒng)進行工程設(shè)計,而這個系統(tǒng)有多個超出你控制范圍的客戶端。
當啟用API版本控制,request.version 屬性將包含與傳入客戶端請求中請求的版本相對應(yīng)的字符串。
默認情況下,版本控制沒有啟用,request.version 將總是返回 None。
如何改變API的行為取決于你自己,但是一個你通常想要的例子是在新版本中切換到不同的序列化樣式。例如:
def get_serializer_class(self):
if self.request.version == 'v1':
return AccountSerializerVersion1
return AccountSerializer
REST framework 包含的 reverse 函數(shù)與版本控制方案相關(guān)聯(lián)。你需要確保將當前 request 作為關(guān)鍵字參數(shù)傳遞進去,如下所示。
from rest_framework.reverse import reverse
reverse('bookings-list', request=request)
上述函數(shù)將應(yīng)用任何適用于請求版本的URL轉(zhuǎn)換。例如:
當將超鏈接序列化樣式與基于URL的版本控制方案一起使用時,請確保將請求作為上下文包含在序列化程序中。
def get(self, request):
queryset = Booking.objects.all()
serializer = BookingsSerializer(queryset, many=True, context={'request': request})
return Response({'all_bookings': serializer.data})
這樣做將會在任何返回的URL中包含適當?shù)陌姹究刂啤?/p>
版本控制方案由settings中的DEFAULT_VERSIONING_CLASS為key來配置。
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'
}
除非顯式設(shè)置,否則DEFAULT_VERSIONING_CLASS將會是None。在這種情況下request.version屬性將總是返回None。
還可以在單個視圖上設(shè)置版本控制方案。通常不需要這樣做,因為全局使用單一版本控制方案更有意義。如果確實需要這樣做,請在視圖類中使用versioning_class屬性。
class ProfileList(APIView):
versioning_class = versioning.QueryParameterVersioning
以下設(shè)置的key也用于控制版本控制:
你還可以通過自定義版本控制方案并使用default_version,allowed_versions和version_param類變量,在每個視圖或每個視圖集的基礎(chǔ)上設(shè)置版本類加上這三個值。例如,如果你想使用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
此方案要求客戶端在Accept header 中將版本指定為媒體類型的一部分。該版本作為媒體類型參數(shù)包含在內(nèi),它補充了主要媒體類型。
下面是一個使用accept header版本化樣式的HTTP請求示例。
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
在上面的示例請求中request.version屬性將返回字符串'1.0'。 基于 accept headers 的版本控制通常被認為是最佳實踐,盡管其他版本控制方式可能適合你的客戶端需求。
嚴格地說json媒體類型未指定為包含其他參數(shù)。如果要構(gòu)建明確指定的公共API,則可以考慮使用vendor media type。為此,請將渲染器配置為使用自定義媒體類型的基于JSON的渲染器:
class BookingsAPIRenderer(JSONRenderer):
media_type = 'application/vnd.megacorp.bookings+json'
你的客戶端請求現(xiàn)在會是這樣的:
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/vnd.megacorp.bookings+json; version=1.0
此方案要求客戶端將版本指定為URL路徑的一部分。
GET /v1/bookings/ HTTP/1.1
Host: example.com
Accept: application/json
你的URL conf中必須包含一個使用'version'關(guān)鍵字參數(shù)的匹配模式,,以便版本控制方案可以使用此版本信息。
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'
)
]
對于客戶端,此方案與URLPathVersioning相同。唯一的區(qū)別是,它是如何在 Django 應(yīng)用程序中配置的,因為它使用URL conf中的命名空間而不是URL conf中的關(guān)鍵字參數(shù)。
GET /v1/something/ HTTP/1.1
Host: example.com
Accept: application/json
使用此方案,request.version 屬性是根據(jù)與傳入請求的路徑匹配的 namespace 確定的。
在下面的示例中,我們給一組視圖提供了兩個可能出現(xiàn)的不同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可能更容易管理。
主機名版本控制方案要求客戶端將請求的版本指定為URL中主機名的一部分。 例如,以下是對http://v1.example.com/bookings/的HTTP請求:
GET /bookings/ HTTP/1.1
Host: v1.example.com
Accept: application/json
默認情況下,此實現(xiàn)期望主機名與以下簡單正則表達式匹配:
^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$
注意,第一組用括號括起來,表示這是主機名的匹配部分。
HostNameVersioning這種方案在調(diào)試模式下使用方案可能會很尷尬,因為你通常會訪問原始IP地址,例如127.0.0.1。有各種在線教程,介紹使用自定義子域名訪問本地主機,這種情況下你可能會發(fā)現(xiàn)這很有幫助。
如果你有基于版本將傳入請求路由到不同服務(wù)器的需求,那么基于主機名的版本控制會特別有用,因為你可以為不同的 API 版本配置不同的 DNS 記錄。
此方案是一種在 URL 中包含版本信息作為查詢參數(shù)的簡單方案。例如: This scheme is a simple style that includes the version as a query parameter in the URL. For example:
GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
要實現(xiàn)自定義版本控制方案,請繼承 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的確定方式。為此,你還應(yīng)該重寫類中的.reverse()方法。有關(guān)示例,請參見源代碼。
更多建議: