第 13 篇:DRF 框架之 API 版本管理
API 不可能一成不变,无论是新增或者删除已有 API,都会对调用它的客户端产生影响。如果对 API 的增删没有管理,随着 API 的增增减减,调用它的客户端就会逐渐陷入迷茫,到底哪个 API 是可用的?为什么之前可用的 API 又不可用了,新增了哪些 API 可以使用?为了方便 API 的管理,我们引入版本功能。
给 API 打上版本号,在某个特定版本下,原来已有的 API 总是可用的。如果要对 API 做重大变更,可以发布一个新版本的 API,并及时提醒用户 API 已变更,敦促用户迁移到新的 API,这样可以给客户端提供一个缓冲过渡期,不至于昨天能用的 API,今天突然报错了。
django-rest-framework 提供了多个 API 版本辅助类,分别实现不同的 API 版本管理方式。比较实用的有:
AcceptHeaderVersioning
这个类要求客户端在 HTTP 的 Accept 请求头加上版本号以表明想请求的 API 版本,例如如下请求:
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
这将请求版本号为 1.0 的接口。
URLPathVersioning
这个类要求客户端在请求的 url 中指定版本号,一个缺点是你在书写 URL 模式时,必须包含关键字为 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
类似,只不过版本号不是在 URL 模式中指定,而是通过 namespace
参数指定 (稍后我们将看到它的具体用法)。
当然,django-rest-framework 还提供了其它诸如 HostNameVersioning
、QueryParameterVersioning
的版本管理辅助类,可自行查看文档了解:https://www.django-rest-framework.org/api-guide/versioning/
综合来看,NamespaceVersioning
模式便于 URL 的设计与管理,因此我们的博客应用决定采用这种 API 版本管理方式。
为了开启 api 版本管理,在项目的配置中加入如下配置:
settings/common.py
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning',
'DEFAULT_VERSION': 'v1'
}
以上两项设置分别全局指定使用的 API 版本管理方式和客户端缺省版本号的情况下默认请求的 API 版本。尽管这些配置项也可以在单个视图或者视图集的范围内指定,但是,统一的版本管理模式更为可取,因此我们在全局配置中指定。
接着在注册的 API 接口前带上版本号:
blogproject/urls.py
urlpatterns = [
# ...
path("api/v1/", include((router.urls, "api"), namespace="v1")),
]
注意这里比之前多了个 namespace
参数,参数值为 v1,代表包含的 URL 模式均属于 v1 这个命名空间。还有一点需要注意,对于 include
函数,如果指定了 namespace
的值,第一个参数必须是一个元组,形式为:(url_patterns, app_name),这里我们将 app_name 指定为 api。
一旦我们开启了版本管理,所有请求对象 request 就会多出一个属性 version
,其值为用户请求的版本号(如果没有指定,就为默认的 DEFAULT_VERSION
的值)。因此,我们可以在请求中针对不同版本的请求执行不同的代码逻辑。比如我们的博客修改文章列表 API,序列化器对返回数据的字段做了一些改动,发布在版本 v2,那么可以根据用户用户请求的版本,返回不同的数据,即新增了 API,又保持对原 api 的兼容:
if request.version == 'v1':
return PostSerializerV1()
return PostSerializer
if 分支可以视为一段临时代码,我们可以通过适当的方式提醒用户,API 已经更改,请尽快迁移到新的版本 v2,并且在未来的某个时间,确认大部分用户都成功迁移到新版api后移除掉这些代码,并将默认版本设为v2,这样原本的 v1 版本的 API 就彻底被废弃了。
当然,我们目前的博客接口还暂时没有需要修改升级的地方,不过为了测试 API 版本管理的设置是否生效了,我们认为添加一个测试用的视图集,在里面做针对不同版本请求的处理,看看不同版本的请求下是否会返回符合预期的不同内容。
首先在 blog/views.py 中加一个简单的测试视图集,这个视图集中有个测试用的接口,接口处理逻辑是根据不同的版本号,返回不同的内容:
class ApiVersionTestViewSet(viewsets.ViewSet):
@action(
methods=["GET"], detail=False, url_path="test", url_name="test",
)
def test(self, request, *args, **kwargs):
if request.version == "v1":
return Response(
data={
"version": request.version,
"warning": "该接口的 v1 版本已废弃,请尽快迁移至 v2 版本",
}
)
return Response(data={"version": request.version})
当然视图集别忘了在 router 中注册:
blogproject/urls.py
# 仅用于 API 版本管理测试
router.register(
r"api-version", blog.views.ApiVersionTestViewSet, basename="api-version"
)
这相当于一次接口版本升级,我们再加入 v2 命名空间的接口:
urlpatterns = [
path("api/v1/", include((router.urls, "api"), namespace="v1")),
path("api/v2/", include((router.urls, "api"), namespace="v2")),
]
可以看到,包含的 URL 都是一样的,只是 namespace 是 v2。
来测试一下效果,启动开发服务器,先访问版本号为 v1 的测试接口,请求返回结果如下,可以看到如期返回了 v1 版本下的内容:
GET /api/v1/api-version/test/
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"version": "v1",
"warning": "该接口的 v1 版本已废弃,请尽快迁移至 v2 版本"
}
再访问版本号为 v2 的测试接口,返回的内容就是 v2 了。
GET /api/v2/api-version/test/
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"version": "v2"
}
对于其它接口,无论 v1,v2 版本的接口均可以访问,这样就相当于完成了一次兼容的接口升级。
关注公众号加入我们
第 13 篇:DRF 框架之 API 版本管理的更多相关文章
- Yii2框架RESTful API教程(二) - 格式化响应,授权认证和速率限制
之前写过一篇Yii2框架RESTful API教程(一) - 快速入门,今天接着来探究一下Yii2 RESTful的格式化响应,授权认证和速率限制三个部分 一.目录结构 先列出需要改动的文件.目录如下 ...
- DRF框架之序列化器初体验
首先,我们需要明白序列化和反序列化的过程指的是什么. 序列化操作:将模型数据 ---> 字典数据 --->JSON数据(响应JSON数据的操作) 反序列化操作:将JSON数据 ---> ...
- 剖析虚幻渲染体系(13)- RHI补充篇:现代图形API之奥义与指南
目录 13.1 本篇概述 13.1.1 本篇内容 13.1.2 概念总览 13.1.3 现代图形API特点 13.2 设备上下文 13.2.1 启动流程 13.2.2 Device 13.2.3 Sw ...
- DRF框架之使用Django框架完成后端接口(API)的定义
学习DRF框架,首先我们就需要明白为什么要学习这个框架. 接下来我们就先用原生的Django框架来定义一个符合RESTful设计方法的接口(API). RESTful接口的需求如下: GET /boo ...
- DRF框架(django rest framework)
1,DRF框架? Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具.通常简称为DRF框架 或 REST framework. Django REST ...
- drf框架总结复习(1)
Serializers 序列化组件 为什么要用序列化组件 当我们做前后端分离的项目~~我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式. 那么我们给前端数据的时候都要转成j ...
- DRF框架 之基础配置
Vue框架的总结 """ 1.vue如果控制html 在html中设置挂载点.导入vue.js环境.创建Vue对象与挂载点绑定 2.vue是渐进式js框架 3.vue指令 ...
- Yii2框架RESTful API教程(一) - 快速入门
前不久做一个项目,是用Yii2框架写一套RESTful风格的API,就去查了下<Yii 2.0 权威指南 >,发现上面写得比较简略.所以就在这里写一篇教程贴,希望帮助刚接触Yii2框架RE ...
- CLion之C++框架篇-优化框架,引入boost(三)
背景 结合上一篇CLion之C++框架篇-优化框架,单元测试(二),继续进行框架优化!这一版优化引入一个我们日常经常使用的操作库Boost,估算使用频率在70%以上! Boost的优势在哪 ...
随机推荐
- mac Pycharm 导入jieba报错解决
背景 新买的mac 用的还不是太熟,在用jieba做分词的时候,pycharm import说是没有安装,那我就直接点击安装呗,结果失败,说是当前渠道不能识别,ok,那我就开始一步一步来解决了. 正文 ...
- dart快速入门教程 (7.3)
7.4.抽离类为单独文件 新建一个文件,单独存放一个类,例如:Person类抽离到person.dart文件中 class Person { final String name; final num ...
- Chrome插件Postman的数据目录存储位置,记一次重装系统后找回postman数据的过程...
有次重装系统到一块新的SSD磁盘,很多数据都做了备份就是忘记将Chrome插件Postman的数据做备份,导致重装后找不到以前定义的那些Collections.悔恨之余想到既然我原来的C盘还在,为何不 ...
- JavaScript基础数组的字面声名法(010)
1.两种方法的对比 数组在JavaScript中,就像大多数的其它语言 一样,是对象.我们可以使用JavaScript内置的数组构造函数Array()来创建数组.就象对象的字面声名法一样,数组也可以采 ...
- socket 建立网络连接,client && server
client代码: package socket; import java.io.IOException; import java.net.Socket; /** * 客户端_聊天室 * * @aut ...
- web页面弹出遮罩层,通过js或css禁止蒙层底部页面跟随滚动
场景概述 弹窗是一种常见的交互方式,而蒙层是弹窗必不可少的元素,用于隔断页面与弹窗区块,暂时阻断页面的交互.但是,在蒙层元素中滑动的时候,滑到内容的尽头时,再继续滑动,蒙层底部的页面会开始滚动,显然这 ...
- YAML & JSON &XML如何选择
前言 本文翻译https://www.csestack.org/yaml-vs-json-vs-xml-difference/,下文会针对当前现有的数据序列化语言做下梳理.重点突出YAML是什么,优缺 ...
- day16 本日作业+周末作业
目录 1.编写计数器功能,要求调用一次在原有的基础上加1 2.周末作业 1.编写计数器功能,要求调用一次在原有的基础上加1 def func(): x=0 def counter(): nonloca ...
- Idea JAVA开发工具快速上手-常用快捷键汇总
前言: 之前一直使用Eclipse 系列开发IDE工具,由于eclipse是开源的所以,一般情况,eclipse基本上每一个java入门者的首选开发工具,其次 Myeclipse.不过现在越来越多的人 ...
- CTF_show平台 web题解 part2
web10 WITH ROLLUP 绕过 点击取消键弹出源码下载: 源码如下: <?php $flag=""; function replaceSpecialChar($st ...