Web后端規(guī)范
不久將來愧沟,整個行業(yè)存在的唯一目的就是消費平臺上的數(shù)據(jù)蔬咬。你的API越容易使用鲤遥,那么就 會有越多的人去用它。立足現(xiàn)在林艘,展望未來盖奈,restful風格的api是我們必然的趨勢。
定義
- 資源: 一個對象的實例
- 集合:一群同種對象
- HTTP:跨網(wǎng)絡的通信協(xié)議
- 客戶端:可以創(chuàng)建HTTP請求的客戶端應用程序
- 第三方開發(fā)者:這個開發(fā)者不屬于你的項目但是有想使用你的數(shù)據(jù)
- 服務器:一個HTTP服務器或者應用程序狐援,客戶端可以跨網(wǎng)絡訪問它
- 端點:這個API在服務器上的URL用于表達一個資源或者一個集合
- 冪等:無邊際效應钢坦,多次操作得到相同的結(jié)果
- URL段:在URL里面已斜杠分隔的內(nèi)容
URL
URI 表示資源,資源一般對應服務器端領(lǐng)域模型中的實體類啥酱。
URL規(guī)范
- 不用大寫字符
- 只用下劃線
_
連接 - 名詞表示資源的集合爹凹,使用復數(shù)
資源集合,單個資源
資源集合
/zooms/ # 所有動物園
/zooms/1/employees/ # id為1的動物園的所有職工
單個資源
/zooms/1/ # id為1的動物園
避免層級過深的url
/
在url中表達層級镶殷,用于按實體關(guān)聯(lián)關(guān)系進行對象導航禾酱,一般根據(jù)id導航。
過深的導航容易導致url膨脹批钠,不易維護宇植,如 GET /zooms/1/areas/3/animals/4, 盡量使用查詢參數(shù)代替路徑中的實體導航埋心,如GET /animals/?zoom=1&area=3指郁。
Request
動詞
五個非常重要的HTTP動詞必須知道
- GET (選擇):從服務器上獲取一個具體的資源或者一個資源列表,具備冪等性
- POST (創(chuàng)建): 在服務器上創(chuàng)建一個新的資源拷呆, 不具備冪等性
- PUT (更新):以整體的方式更新服務器上的一個資源闲坎, 具備冪等性
- PATCH (部分更新):只更新服務器上一個資源的部分屬性, 具備冪等性
- DELETE (刪除):刪除服務器上的一個資源茬斧, 具備冪等性
原則上腰懂,只允許客戶端或者第三方調(diào)用者使用這五個HTTP動詞進行數(shù)據(jù)交互,并且在URL段 里面不出現(xiàn)任何其他的動詞项秉。有寫操作的動詞性很強绣溜, 不太容易用一個名詞來表述,可以 邏輯上換一個方式來處理娄蔼,比如作廢一張訂單怖喻,可以采用兩種方式來實現(xiàn)。一是修改訂單的 狀態(tài)和相關(guān)字段(PATCH方法岁诉,這種的業(yè)務邏輯性不強锚沸,不清晰,不推薦)涕癣,另一種是把作廢 的訂單看作一種邏輯資源哗蜈,只需要在這種資源集合中使用POST方法創(chuàng)建一個資源即可。
另外一般情況下,GET請求要考慮緩存(客戶端距潘,服務器都要考慮)炼列,減少服務器檢索數(shù)據(jù)的 壓力。
版本化
API是服務器與客戶端之間的一個公共契約音比。對服務器上的API做了一個更改唯鸭,并且這些更改 無法向后兼容,那么就打破了這個契約硅确。這時候既要確保應用程序逐步的演變,又要讓客戶 端繼續(xù)可用明肮。那么必須在引入新版本API的同時保持舊版本API仍然可用菱农。所以接口必須版本 化
- 如果只是簡單的增加一個新的特性到API上,如資源上的一個新屬性或者增加一個新的端 點柿估,不需要增加API的版本循未。因為這些并不會造成向后兼容性的問題,只需要修改文檔即可秫舌。
- 申明不支持一個特性并不意味著關(guān)閉或者破壞它的妖。而是告訴客戶端舊版本的API將在某個 特定的時間被刪除,并且建議他們使用新版本的API足陨。
- 在URL中包含版本信息
GET /v1/zooms/ GET /v2/zooms/1/animals/
UserAgent
所有請求的Header信息中必須按照格式填寫User-Agent信息嫂粟,格式:
type|os|os_version|product|version|...
說明:
-
type
: 客戶端類型, [MOBILE, DESKTOP, BROWSER] -
os
: 操作系統(tǒng), [Android, iOS, Chrome, IE ...] -
os_version
: 操作系統(tǒng)版本號, 包含完整信息,比如:Windows 7 Ultimate Service Pack 1 64bit -
product
: 產(chǎn)品, [KLICEN_APP, ZEUS(宙斯系統(tǒng)),ZEUS_APP(宙斯系統(tǒng)App), KLICEN_EP(凱勵程企業(yè)版) ,INSTALL(安裝工具), VUS(欣悅途), EWS(預警系統(tǒng))] -
version
: 客戶端版本號
手機端必須增加 手機品牌|手機型號|屏幕分辨率
沒有的用空表示墨缘;必須包含前面五個字段星虹。例如:
"User-Agent": "MOBILE|Android|7.0|KLICEN_APP|2.2.5|Dalvik/2.1.0 (Linux; U; Android 7.0; FRD-AL00 Build/HUAWEIFRD-AL00)|1080*1794|863549034263964"
Response
內(nèi)容類型
接口只提供兩種類型的返回內(nèi)容
- 全部接口默認支持json
- 部分接口支持excel表格/csv,數(shù)據(jù)導出作為一種返回格式镊讼,導出權(quán)限可配置
/animals/?zoom=1&format=excel # 導出id為1的動物園的所有動物數(shù)據(jù)
### 預期返回的內(nèi)容 - GET /collection/?page=1&page_size=15: 返回一系列資源對象宽涌,分頁
- GET /collection/resource/: 返回單獨的資源對象
- POST /collection/: 返回新創(chuàng)建的資源對象
- PUT /collection/resource/: 返回完整的資源對象
- PATCH /collection/resource/: 返回完整的資源對象
- DELETE /collection/resource/: 返回一個空文檔
使用ISO8601的國際化時間格式
接收和返回時間數(shù)據(jù)時只使用UTC格式
"create_at": "2012-01-01T12:00:00Z"
枚舉型
枚舉類型的字段返回其名值對:
{
"key": 存儲值,
"verbose": 顯示值
}
提供標準的時間戳
提供默認的資源創(chuàng)建時間,更新時間 created_at and updated_at, 例如:
{
...
"created_at": "2012-01-01T12:00:00Z",
"updated_at": "2012-01-01T13:00:00Z",
...
}
這些時間戳可能不適用于某些資源蝶棋,這種情況下可以忽略省去卸亮。
包裝
response 的 body 統(tǒng)一做如下包裝。示例:
{
"code": 0,
"msg": "請求成功"(用戶友好),
"data": {
"id": 1,
"name": "張三"
}
}
使用djangorestframework的情況下玩裙,可以在配置文件中配置REST_FRAMEWORK
中的DEFAULT_RENDERER_CLASSES
為utils.renders.CustomJsonRender
, 它的具體實現(xiàn)如下:
# -*- coding: utf-8 -*-
from rest_framework.renderers import JSONRenderer
class CustomJsonRender(JSONRenderer):
""" 自定義返回數(shù)據(jù) Json格式
{
"code": 0,
"msg": "success",
"data": { ... }
}
"""
def render(self, data, accepted_media_type=None, renderer_context=None):
if renderer_context:
response = renderer_context['response']
code = 0 if int(response.status_code / 100) == 2 else response.status_code
msg = 'success'
if isinstance(data, dict):
msg = data.pop('msg', msg)
code = data.pop('code', code)
data = data.pop('data', data)
if code != 0 and data:
msg = data.pop('detail', 'failed')
response.status_code = 200
res = {
'code': code,
'msg': msg,
'data': data,
}
return super().render(res, accepted_media_type, renderer_context)
else:
return super().render(data, accepted_media_type, renderer_context)
可能的錯誤信息的code
可根據(jù)實際情況擴展, 所以要讓客戶端能獲取到這些code
兼贸。
code碼
- 0 OK - [GET]: 客戶端向服務器請求獲取數(shù)據(jù)成功
- 201 CREATED - [POST/PUT/PATCH]: 客戶端向服務器請求改變數(shù)據(jù)成功
- 204 NO CONTENT - [DELETE]: 客戶端要求服務器刪除一個資源,服務器刪除成功
- 400 BAD REQUEST - [POST/PUT/PATCH]: 客戶端向服務器提供了不正確的數(shù)據(jù)献酗,服務器什么也不做
- 401 UNAUTHORIZED - [*]: 用戶未認證
- 403 FORBIDDEN - [*]: 已認證但權(quán)限不夠
- 404 NOT FOUND - [*]: 客戶端引用了一個不存在的資源或集合
- 500 INTERNAL SERVER ERROR - [*]: 服務器發(fā)生內(nèi)部錯誤寝受,客戶端無法得知結(jié)果,請求可能已經(jīng)處理成功
嵌套外鍵關(guān)系
序列化的外鍵關(guān)系建立在一個有嵌套關(guān)系的對象之上, 例如:
{
"name": "成都動物園",
"manager": {
"id": 1
},
...
}
而不是這樣, 例如:
{
"name": "成都動物園",
"owner_id": 1,
...
}
這種方式把相關(guān)聯(lián)的資源信息內(nèi)聯(lián)在一起罕偎,在返回更多信息時不用改變響應資源的結(jié)構(gòu), 例如:
{
"name": "成都動物園",
"owner": {
"id": 1,
"name": "張三",
"email": "zhangsan@klicen.com"
},
...
}
文檔
- 避免使用文檔自動化生成器很澄,即便用了,你也要保證自己審閱過并讓它具有更好的版式。
- 不要截斷示例中請求與響應的內(nèi)容甩苛,展示完整的東西蹂楣。并在文檔中使用高亮語法。
- API的驗證授權(quán),包含獲取及使用驗證tokens
- API穩(wěn)定性及版本控制, 包含如何選擇所需要的版本
- 正確的響應和錯誤的響應都應該文檔化讯蒲,并說明在什么情況下會產(chǎn)生這些的錯誤
如果時間允許痊土,甚至可以創(chuàng)建一個控制臺來讓開發(fā)者可以立即體驗一下API的功能。
API分析
API分析就是持續(xù)跟蹤那些正為人使用的API的版本和端點信息墨林,這樣做的好處是:
- 決定什么時候不再支持某個版本
- 找到那些使用最廣泛的API赁酝,用其作為指導業(yè)務方向或者優(yōu)化效率的重要的依據(jù)
- 更多...
認證與安全
認證
采用OAuth2.0,OAuth2.0提供了一個非常好的方法去做這件事旭等。在每一個請求里酌呆, 你可以明確知道哪個客戶端創(chuàng)建了請求,哪個用戶提交了請求搔耕,并且提供了一種標準的訪問 過期機制或允許用戶從客戶端注銷隙袁,所有這些都不需要第三方的客戶端知道用戶的登陸認證 信息。
安全
這個暫時不是當前的重點弃榨,這里只列出幾個方向菩收,后期再完善
- 采用https
- 訪問頻次的控制
- api訪問記錄的跟蹤分析