版本控制-Django REST框架
versioning.py
版本化
对接口进行版本化只是一种“礼貌”的方式来杀死已部署的客户端。
— 罗伊·菲尔丁.
API版本控制允许您更改不同客户端之间的行为。REST框架提供了许多不同的版本控制方案。
版本控制由传入的客户端请求确定,可以基于请求URL,也可以基于请求头。
有许多有效的方法来处理版本控制。非版本化的系统也可能是适当的。,特别是如果您正在为具有多个客户端的长期系统进行工程,而这些客户不在您的控制范围之内。
使用REST框架进行版本控制
当启用API版本控制时,request.version
属性将包含与传入客户端请求中请求的版本相对应的字符串。
默认情况下,不启用版本控制,并且request.version
永远都会回来None
.
基于版本的变化行为
如何改变API行为取决于您自己,但您通常想要的一个示例是在更新版本中切换到不同的序列化样式。例如:
def get_serializer_class(self):if self.request.version == 'v1':return AccountSerializerVersion1return AccountSerializer
反转版本API的URL
这个function reverse() { [native code] }
REST框架包含的函数与版本控制方案相关联。您需要确保包含当前request
作为关键字参数,就像这样。
from rest_framework.reverse import reversereverse('bookings-list', request=request)
上面的函数将应用任何适合于请求版本的URL转换。例如:
- 如果
NamespaceVersion
正在使用,而API版本是“v1”,那么所使用的URL查找将是'v1:bookings-list'
,它可能解析为如下所示的URLhttp://example.org/v1/bookings/
. - 如果
查询参数化
正在使用的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
类变量。例如,如果您想使用URLPathVersion
:
from rest_framework.versioning import URLPathVersioning
from rest_framework.views import APIViewclass ExampleVersioning(URLPathVersioning):default_version = ...allowed_versions = ...version_param = ...class ExampleView(APIVIew):versioning_class = ExampleVersioning
API参考
AcceptHeaderVersion
此方案要求客户端将版本指定为Accept
头球。该版本作为媒体类型参数包括在内,该参数补充了主媒体类型。
下面是一个使用Accept报头版本控制样式的HTTP请求示例。
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
在上面的示例请求中request.version
属性将返回字符串。'1.0'
.
基于接受标头的版本控制是一般认为如最佳做法,尽管其他样式可能适合于您的客户需求。
将AccepHeader与供应商媒体类型一起使用
严格地说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
URLPathVersion
此方案要求客户端将版本指定为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')
]
NamespaceVersion
对于客户端,此方案与URLPathVersion
...唯一的区别是如何在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'))
]
双管齐下URLPathVersion
和NamespaceVersion
如果您只需要一个简单的版本控制方案,则是合理的。这个URLPathVersion
方法可能更适合于小型临时项目,而NamespaceVersion
对于大型项目来说,可能更容易管理。
HostNameVersion
主机名版本控制方案要求客户端将请求的版本指定为URL中主机名的一部分。
例如,下面是对http://v1.example.com/bookings/
URL:
GET /bookings/ HTTP/1.1
Host: v1.example.com
Accept: application/json
默认情况下,此实现期望主机名与这个简单的正则表达式匹配:
^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$
请注意,第一组包含在括号中,表明这是主机名的匹配部分。
这个HostNameVersion
在调试模式中使用方案可能会很尴尬,因为通常您将访问原始ip地址,如127.0.0.1
...关于如何具有自定义子域的访问本地主机在这种情况下你可能会觉得很有帮助。
如果需要根据版本将传入请求路由到不同的服务器,则基于主机名的版本控制可能特别有用,因为您可以为不同的API版本配置不同的DNS记录。
查询参数化
此方案是一种简单的样式,它将版本作为查询参数包含在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()
方法。有关示例,请参阅源代码。