首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >django-rest-framework: api版本控制

django-rest-framework: api版本控制
EN

Stack Overflow用户
提问于 2013-01-11 08:24:19
回答 3查看 20.5K关注 0票数 42

因此,谷歌一下,似乎普遍的共识是,在REST URI中嵌入版本号是一种糟糕的做法,也是一个糟糕的想法。

尽管如此,还是有强烈的支持者支持这一点。

例如Best practices for API versioning?

我的问题是如何使用django-rest-framework中的accept header / content协商来实现所提出的解决方案。

它看起来像框架中的内容协商,

http://django-rest-framework.org/api-guide/content-negotiation/已配置为根据接受的MIME类型自动返回目标值。如果我开始使用自定义类型的Accept头,我将失去框架的这一好处。

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-17 21:17:23

这样做的一种方法是将版本控制指定为媒体类型的一部分。

这就是GitHub currently do for their API

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

在API中有许多不同的版本控制模式,我不会说围绕正确的方法有任何伟大的共识,但这是一种合理的可能性。

更新2015年1月:3.1.0版本中将引入更好的版本支持。查看此拉取请求

更新2015年3月:版本控制API are now available的文档。

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

票数 33
EN

Stack Overflow用户

发布于 2014-02-18 05:42:45

更新:

versioning现在得到了正确的支持。

以下是您的链接中的一些答案:

我们发现把版本放在网址中是实用和有用的。它让你很容易一眼就知道你在用什么。我们将别名/foo添加到/foo/(最新版本),以便于使用,更短/更干净的URL,等等,正如公认的答案所建议的那样。永远保持向后兼容性通常是成本高昂和/或非常困难的。我们更喜欢提前通知弃用,重定向,文档和其他机制。

因此,我们采用了这种方法,并允许客户端在请求头(X- version )中指定版本,下面是我们是如何做到的:

API应用程序中的结构:

代码语言:javascript
复制
.
├── __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

project urls.py:

代码语言:javascript
复制
url(r'^api/', include('project.api.urls', namespace='api')),

接口应用层urls.py:

代码语言:javascript
复制
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')),
)

版本级别urls.py

代码语言:javascript
复制
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

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

代码语言:javascript
复制
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)

示例url:

代码语言:javascript
复制
curl -H "X-Version: v1" http://your.domain:8000/api/myaccount/
票数 46
EN

Stack Overflow用户

发布于 2021-04-13 22:50:54

@James Lin给了一个很好的回答。在对答案的评论中,@Mar0ux询问了如何处理损坏的HyperlinkedRelatedField字段。

我修复了这个问题,将HyperlinkedRelatedField更改为SerializerMethodField,并通过向其传递额外的参数current_app来调用reverse (非常不明显)。

例如,我有一个应用程序'fruits_ app ',命名空间版本为'v1','v2‘。我有水果模型的序列化程序。因此,为了序列化url,我创建了一个字段

代码语言:javascript
复制
url = serializers.SerializerMethodField()

和相应的方法:

代码语言:javascript
复制
def get_url(self, instance):
    reverse.reverse('fruits_app:fruit-detail',
        args=[instance.pk],
        request=request,
        current_app=request.version)

对于嵌套的名称空间,您将需要更改,将这些名称空间添加到current_app。例如,如果你有一个应用程序'fruits_app‘,其命名空间版本为'v1','v2',实例命名空间为'bananas’,则序列化水果url的方法如下所示:

代码语言:javascript
复制
def get_url(self, instance):
    reverse.reverse('fruits_app:fruit-detail',
        args=[instance.pk],
        request=request,
        current_app='bananas:{}'.format(request.version))
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14269719

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档