DRF框架API版本管理實(shí)現(xiàn)方法解析
API 不可能一成不變,無(wú)論是新增或者刪除已有 API,都會(huì)對(duì)調(diào)用它的客戶(hù)端產(chǎn)生影響。如果對(duì) API 的增刪沒(méi)有管理,隨著 API 的增增減減,調(diào)用它的客戶(hù)端就會(huì)逐漸陷入迷茫,到底哪個(gè) API 是可用的?為什么之前可用的 API 又不可用了,新增了哪些 API 可以使用?為了方便 API 的管理,我們引入版本功能。
給 API 打上版本號(hào),在某個(gè)特定版本下,原來(lái)已有的 API 總是可用的。如果要對(duì) API 做重大變更,可以發(fā)布一個(gè)新版本的 API,并及時(shí)提醒用戶(hù) API 已變更,敦促用戶(hù)遷移到新的 API,這樣可以給客戶(hù)端提供一個(gè)緩沖過(guò)渡期,不至于昨天能用的 API,今天突然報(bào)錯(cuò)了。
django-rest-framework 提供了多個(gè) API 版本輔助類(lèi),分別實(shí)現(xiàn)不同的 API 版本管理方式。比較實(shí)用的有:
AcceptHeaderVersioning
這個(gè)類(lèi)要求客戶(hù)端在 HTTP 的 Accept 請(qǐng)求頭加上版本號(hào)以表明想請(qǐng)求的 API 版本,例如如下請(qǐng)求:
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
這將請(qǐng)求版本號(hào)為 1.0 的接口。
URLPathVersioning
這個(gè)類(lèi)要求客戶(hù)端在請(qǐng)求的 url 中指定版本號(hào),一個(gè)缺點(diǎn)是你在書(shū)寫(xiě) URL 模式時(shí),必須包含關(guān)鍵字為 version 的模式,例如官網(wǎng)的一個(gè)例子:
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'
)
]
這樣的話(huà)很不方便,因此我們一般不使用。
NamespaceVersioning
和上面提到的 URLPathVersioning 類(lèi)似,只不過(guò)版本號(hào)不是在 URL 模式中指定,而是通過(guò) namespace 參數(shù)指定 (稍后我們將看到它的具體用法)。
當(dāng)然,django-rest-framework 還提供了其它諸如 HostNameVersioning、QueryParameterVersioning 的版本管理輔助類(lèi),可自行查看文檔了解:https://www.django-rest-framework.org/api-guide/versioning/
綜合來(lái)看,NamespaceVersioning 模式便于 URL 的設(shè)計(jì)與管理,因此我們的博客應(yīng)用決定采用這種 API 版本管理方式。
為了開(kāi)啟 api 版本管理,在項(xiàng)目的配置中加入如下配置:
settings/common.py
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning',
'DEFAULT_VERSION': 'v1'
}
以上兩項(xiàng)設(shè)置分別全局指定使用的 API 版本管理方式和客戶(hù)端缺省版本號(hào)的情況下默認(rèn)請(qǐng)求的 API 版本。盡管這些配置項(xiàng)也可以在單個(gè)視圖或者視圖集的范圍內(nèi)指定,但是,統(tǒng)一的版本管理模式更為可取,因此我們?cè)谌峙渲弥兄付ā?/p>
接著在注冊(cè)的 API 接口前帶上版本號(hào):
blogproject/urls.py
urlpatterns = [
# ...
path("api/v1/", include((router.urls, "api"), namespace="v1")),
]
注意這里比之前多了個(gè) namespace 參數(shù),參數(shù)值為 v1,代表包含的 URL 模式均屬于 v1 這個(gè)命名空間。還有一點(diǎn)需要注意,對(duì)于 include 函數(shù),如果指定了 namespace 的值,第一個(gè)參數(shù)必須是一個(gè)元組,形式為:(url_patterns, app_name),這里我們將 app_name 指定為 api。
一旦我們開(kāi)啟了版本管理,所有請(qǐng)求對(duì)象 request 就會(huì)多出一個(gè)屬性 version,其值為用戶(hù)請(qǐng)求的版本號(hào)(如果沒(méi)有指定,就為默認(rèn)的 DEFAULT_VERSION 的值)。因此,我們可以在請(qǐng)求中針對(duì)不同版本的請(qǐng)求執(zhí)行不同的代碼邏輯。比如我們的博客修改文章列表 API,序列化器對(duì)返回?cái)?shù)據(jù)的字段做了一些改動(dòng),發(fā)布在版本 v2,那么可以根據(jù)用戶(hù)用戶(hù)請(qǐng)求的版本,返回不同的數(shù)據(jù),即新增了 API,又保持對(duì)原 api 的兼容:
if request.version == 'v1': return PostSerializerV1() return PostSerializer
if 分支可以視為一段臨時(shí)代碼,我們可以通過(guò)適當(dāng)?shù)姆绞教嵝延脩?hù),API 已經(jīng)更改,請(qǐng)盡快遷移到新的版本 v2,并且在未來(lái)的某個(gè)時(shí)間,確認(rèn)大部分用戶(hù)都成功遷移到新版api后移除掉這些代碼,并將默認(rèn)版本設(shè)為v2,這樣原本的 v1 版本的 API 就徹底被廢棄了。
當(dāng)然,我們目前的博客接口還暫時(shí)沒(méi)有需要修改升級(jí)的地方,不過(guò)為了測(cè)試 API 版本管理的設(shè)置是否生效了,我們認(rèn)為添加一個(gè)測(cè)試用的視圖集,在里面做針對(duì)不同版本請(qǐng)求的處理,看看不同版本的請(qǐng)求下是否會(huì)返回符合預(yù)期的不同內(nèi)容。
首先在 blog/views.py 中加一個(gè)簡(jiǎn)單的測(cè)試視圖集,這個(gè)視圖集中有個(gè)測(cè)試用的接口,接口處理邏輯是根據(jù)不同的版本號(hào),返回不同的內(nèi)容:
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 版本已廢棄,請(qǐng)盡快遷移至 v2 版本",
}
)
return Response(data={"version": request.version})
當(dāng)然視圖集別忘了在 router 中注冊(cè):
blogproject/urls.py
blogproject/urls.py # 僅用于 API 版本管理測(cè)試 router.register( r"api-version", blog.views.ApiVersionTestViewSet, basename="api-version" )
這相當(dāng)于一次接口版本升級(jí),我們?cè)偌尤?v2 命名空間的接口:
urlpatterns = [
path("api/v1/", include((router.urls, "api"), namespace="v1")),
path("api/v2/", include((router.urls, "api"), namespace="v2")),
]
可以看到,包含的 URL 都是一樣的,只是 namespace 是 v2。
來(lái)測(cè)試一下效果,啟動(dòng)開(kāi)發(fā)服務(wù)器,先訪問(wèn)版本號(hào)為 v1 的測(cè)試接口,請(qǐng)求返回結(jié)果如下,可以看到如期返回了 v1 版本下的內(nèi)容:
GET /api/v1/api-version/test/
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"version": "v1",
"warning": "該接口的 v1 版本已廢棄,請(qǐng)盡快遷移至 v2 版本"
}
再訪問(wèn)版本號(hào)為 v2 的測(cè)試接口,返回的內(nèi)容就是 v2 了。
GET /api/v2/api-version/test/
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"version": "v2"
}
對(duì)于其它接口,無(wú)論 v1,v2 版本的接口均可以訪問(wèn),這樣就相當(dāng)于完成了一次兼容的接口升級(jí)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用pandas中的DataFrame.rolling方法查看時(shí)間序列中的異常值
Pandas是Python中最受歡迎的數(shù)據(jù)分析和處理庫(kù)之一,提供了許多強(qiáng)大且靈活的數(shù)據(jù)操作工具,在Pandas中,DataFrame.rolling方法是一個(gè)強(qiáng)大的工具,在本文中,我們將深入探討DataFrame.rolling方法的各種參數(shù)和示例,以幫助您更好地理解和應(yīng)用這個(gè)功能2023-12-12
ruff check文件目錄檢測(cè)--exclude參數(shù)設(shè)置路徑詳解
這篇文章主要為大家介紹了ruff check文件目錄檢測(cè)exclude參數(shù)如何設(shè)置多少路徑詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
python數(shù)據(jù)提取BeautifulSoup的概念語(yǔ)法及使用優(yōu)點(diǎn)詳解
這篇文章主要為大家介紹了python數(shù)據(jù)提取BeautifulSoup概念語(yǔ)法及使用優(yōu)點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-02-02
Python實(shí)現(xiàn)在matplotlib中兩個(gè)坐標(biāo)軸之間畫(huà)一條直線光標(biāo)的方法
這篇文章主要介紹了Python實(shí)現(xiàn)在matplotlib中兩個(gè)坐標(biāo)軸之間畫(huà)一條直線光標(biāo)的方法,涉及Python操作matplotlib模塊繪圖的相關(guān)技巧,需要的朋友可以參考下2015-05-05
關(guān)于Python?Tkinter?復(fù)選框?->Checkbutton
這篇文章主要介紹了關(guān)于Python?Tkinter復(fù)選框Checkbutton,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
Python二叉樹(shù)的鏡像轉(zhuǎn)換實(shí)現(xiàn)方法示例
這篇文章主要介紹了Python二叉樹(shù)的鏡像轉(zhuǎn)換實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了二叉樹(shù)鏡像轉(zhuǎn)換的原理及Python相關(guān)算法實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-03-03

