django-rest-framework:api版本控制

w--*_*w-- 32 python api django rest django-rest-framework

因此谷歌搜索似乎普遍的共识是在REST URI中嵌入版本号是一种不好的做法,也是一个坏主意.

即便如此,也有强有力的支持者支持这一点.
例如,API版本控制的最佳实践?

我的问题是如何在django-rest-framework中完成使用accept header/content negotiation的提议解决方案来实现这一目标.

看起来框架中的内容协商,
http://django-rest-framework.org/api-guide/content-negotiation/ 已经配置为根据接受的MIME类型自动返回预期值.如果我开始使用自定义类型的Accept标头,我将失去框架的这种好处.

有没有更好的方法在框架中实现这一目标?

Jam*_*Lin 38

更新:

现在可以正确支持版本控制.


您的链接有一些答案:

我们发现将版本放在URL中是实用且有用的.它可以让您轻松了解您正在使用的内容.我们使用别名/ foo到/ foo /(最新版本)以便于使用,更短/更清洁的URL等,正如接受的答案所暗示的那样.永远保持向后兼容通常是成本过高和/或非常困难的.我们更愿意提前通知弃用,重定向此处建议,文档和其他机制.

所以我们采用这种方法,并允许客户端在请求标头(X-Version)中指定版本,这是我们如何做到的:

API应用程序侧面的结构:

.
??? __init__.py
??? middlewares.py
??? urls.py
??? v1
?   ??? __init__.py
?   ??? account
?   ?   ??? __init__.py
?   ?   ??? serializers.py
?   ?   ??? views.py
?   ??? urls.py
??? v2
    ??? __init__.py
    ??? account
    ?   ??? __init__.py
    ?   ??? serializers.py
    ?   ??? views.py
    ??? urls.py
Run Code Online (Sandbox Code Playgroud)

project urls.py:

url(r'^api/', include('project.api.urls', namespace='api')),
Run Code Online (Sandbox Code Playgroud)

api app level urls.py:

from django.conf.urls import *

urlpatterns = patterns('',
    url(r'', include('project.api.v2.urls', namespace='default')),
    url(r'^v1/', include('project.api.v1.urls', namespace='v1')),
)
Run Code Online (Sandbox Code Playgroud)

版本级别urls.py

from django.conf.urls import *
from .account import views as account_views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('account', account_views.AccountView)
router.register('myaccount', account_views.MyAccountView)
urlpatterns = router.urls
Run Code Online (Sandbox Code Playgroud)

通过更改path_info创建一个中间件以切换到正确的代码,请注意,有一点需要注意,项目级网址中定义的命名空间('api')不灵活,需要在中间件中知道:

from django.core.urlresolvers import resolve
from django.core.urlresolvers import reverse


class VersionSwitch(object):

    def process_request(self, request):
        r = resolve(request.path_info)
        version = request.META.get('HTTP_X_VERSION', False)
        if r.namespace.startswith('api:') and version:
            old_version = r.namespace.split(':')[-1]
            request.path_info = reverse('{}:{}'.format(r.namespace.replace(old_version, version), r.url_name), args=r.args, kwargs=r.kwargs)
Run Code Online (Sandbox Code Playgroud)

示例网址:

curl -H "X-Version: v1" http://your.domain:8000/api/myaccount/
Run Code Online (Sandbox Code Playgroud)

  • 这种方法很好,除了它会破坏超链接字段(`HyperlinkedRelatedField` 等)。有任何想法吗? (2认同)
  • 那么我们在哪里放模型? (2认同)

Tom*_*tie 30

执行此操作的一种方法是将版本控制指定为媒体类型的一部分.

这就是GitHub 目前为其API所做的事情.

您还可以在接受标头中包含媒体类型参数,例如Accept: application/json; version=beta,可以成功匹配的参数JSONRenderer.然后,您可以根据接受的媒体类型对视图进行编码,使其行为不同,请参见此处.

在API中进行版本控制有很多不同的模式,我不会说对于正确的方法有任何很大的共识,但这是一种合理的可能性.


2015年1月更新:更好的版本控制支持将在3.1.0版本中传入.见[此拉动请求]

2015年3月更新:版本控制API的文档现已推出.

(https://github.com/tomchristie/django-rest-framework/pull/2285)了解更多详情.