title: 一聲笑接口文檔
date: 2019-03-03 21:44:43
tags:
Author:Leguang
E-Mail:langmanleguang@qq.com
目標(biāo)
- 接口“粒度”爭取設(shè)計(jì)得足夠小率翅,爭取在業(yè)務(wù)發(fā)生變化后灭将,后臺接口不需要增減榆浓,只需要前端組合接口仍然能滿足新的業(yè)務(wù)需求菇曲。
- 任何一個(gè)接口都可以獲取到數(shù)據(jù)神僵,哪怕沒傳參數(shù)熊经。
要求
命名規(guī)范
一名二姓三風(fēng)水脏榆,四積陰德五讀書猖毫,名不正則言不順,言不順則事難成须喂。軟件開發(fā)其實(shí)就是門命名的藝術(shù)吁断,所以首先定義一些規(guī)范趁蕊,提出一些硬性要求,大家在命名的時(shí)候盡量多花點(diǎn)心思仔役,多參考優(yōu)秀的命名風(fēng)格掷伙。
- 強(qiáng)烈推薦參考:參考阿里巴巴Java開發(fā)手冊,Android開發(fā)規(guī)范又兵,iOS開發(fā)手冊任柜。
- 一個(gè)單詞盡量選擇5--7個(gè)字母的,這樣才最優(yōu)美沛厨。
- 首字母縮寫的單詞盡量每個(gè)字母都用大寫宙地,例如ID。用個(gè)小寫逆皮,人家還以為是一個(gè)單詞宅粥。當(dāng)然uri、url电谣、urn這種除外粹胯,因?yàn)榇蠹叶贾肋@個(gè)是什么。
- 規(guī)范并統(tǒng)一公司的基礎(chǔ)包名與項(xiàng)目的關(guān)系辰企。
- 前后端的某些名稱概念要統(tǒng)一用某一個(gè)單詞,比如支付的統(tǒng)一訂單况鸣,支付寶用的是order牢贸,微信用的是unifiedorder,那我們統(tǒng)一對訂單這個(gè)概念用order這個(gè)詞镐捧。再比如主機(jī):后臺用gateway潜索,現(xiàn)在我們統(tǒng)一用host。這單詞不統(tǒng)一很容易分裂懂酱。
uri規(guī)范
uri 表示資源竹习,資源一般對應(yīng)服務(wù)器端領(lǐng)域模型中的實(shí)體類,要求如下:
- 不用大寫列牺。
- 盡量不用橫杠分隔符整陌,萬一要用,請使用中杠“-”不用下杠“_”瞎领。
- 參數(shù)列表要encode泌辫。
- uri中的名詞表示資源集合,使用復(fù)數(shù)形式九默。
- 路徑僅表示資源的路徑(位置)震放,以及一些特殊的actions操作。
- 以復(fù)數(shù)(名詞)進(jìn)行命名資源驼修,不管返回單個(gè)或者多個(gè)資源殿遂。
- 資源的路徑從父到子依次如:/{resource}/{resource_id}/{sub_resource}/{sub_resource_id}/{sub_resource_property}诈铛。
- 使用?來進(jìn)行資源的過濾、搜索以及分頁等墨礁。
- 使用版本號幢竹,且版本號在資源路徑之前。
- 優(yōu)先使用內(nèi)容協(xié)商來區(qū)分表述格式饵溅,而不是使用后綴來區(qū)分表述格式妨退。
- url最好越簡短越好,結(jié)果過濾蜕企,排序咬荷,搜索相關(guān)的功能都應(yīng)該通過參數(shù)實(shí)現(xiàn)。
- url失效則返回404 not found 或 410 gone轻掩;對遷移的API幸乒,返回 301 重定向。
JSON規(guī)范
暫時(shí)只考慮json的數(shù)據(jù)格式唇牧,要求如下:
- 不要使用縮寫罕扎。
- 統(tǒng)一用駝峰命名法。
- 不要使用“_”或者“-”丐重。
- 用名詞復(fù)數(shù)表示集合類型腔召。
- 為了方便以后的擴(kuò)展兼容,如果返回的是數(shù)組扮惦,強(qiáng)烈建議用一個(gè)包含如items屬性的對象進(jìn)行包裹臀蛛。如:
{"items":[{},{}]}
。 - 建議對每個(gè)字段設(shè)置默認(rèn)值(數(shù)組型可設(shè)置為[],字符串型可設(shè)置為””崖蜜,數(shù)值可設(shè)置為0浊仆,對象可設(shè)置為{}),這一條是為了方便前端/客戶端進(jìn)行判斷字段存不存在操作。
- 建議資源使用UUID最為唯一標(biāo)識豫领。同時(shí)建議命名為id或者uid抡柿。
- 采用UTF-8編碼。
- 數(shù)據(jù)應(yīng)該拿來就能用等恐,不應(yīng)該還要進(jìn)行轉(zhuǎn)換操作洲劣。
草稿:JSON返回的格式是分門別類按對象來劃分,還是鋪大餅的形式鋪開鼠锈,兩者利弊各異闪檬,比如url,可能一個(gè)接口中返回多個(gè)url购笆,如果分json對象裝的話粗悯,則key都可以叫url,否則的話key就得命名成xxxUrl同欠。這個(gè)有待商議
HTTP部分
使用場景
- App的初始化數(shù)據(jù)盡量都用http協(xié)議獲取样傍。
- 頁面的初始化數(shù)據(jù)盡量都用http協(xié)議獲取横缔。
URL結(jié)構(gòu)
https://{serviceRoot}/{module}/{collection}/{id}
- {serviceRoot} – 域名+端口號 (site URL) + 根目錄
- {module} – 模塊名稱
- {collection} – 要訪問的資源
- {id} – 要訪問的資源的唯一編號
公共請求頭
通過Content-Type指定請求與返回的數(shù)據(jù)格式有JSON和XML,暫時(shí)我們只管json的。其中請求數(shù)據(jù)還要指定Accept衫哥。其中額外添加的請求頭里的參數(shù)注意大小寫茎刚。
Accept: application/json
Content-Type: application/json;charset=UTF-8
Token: token_G34G34G34G34G35G5
Application: 應(yīng)用:版本
Platform: Android
Locale: zh
params | 類型 | 是否必要 | 描述 |
---|---|---|---|
Token | String | 是 | 這個(gè)不用解釋了吧? |
Application | String | 是 | App應(yīng)用名稱(名稱有官方指定)與當(dāng)前版本的版本名稱撤逢,中間用半角冒號隔開 |
Platform | String | 是 | Android表示Android平臺膛锭,iOS表示iOS平臺 |
Locale | String | 否 | 用于針對接口的國際化,不同的值代表不同的語言蚊荣,可以不傳初狰,不傳默認(rèn)表示中文簡體。值和語言如下表所示: |
暫時(shí)只考慮4門語言
值 | 意義 |
---|---|
zh | 中文(簡體) |
en | 英文 |
ja | 日文 |
ko | 韓文 |
公共參數(shù)(部分公共參數(shù)建議公放到請求頭里)
公共參數(shù)是指每一個(gè)接口都可能有的互例,為了減少篇幅奢入,我在這里統(tǒng)一定義,同時(shí)后端要指定公共參數(shù)的默認(rèn)值媳叨,且要保證沒有傳公共參數(shù)不會報(bào)錯(cuò)腥光,所以需要一定的容錯(cuò)性,比如priceDes這個(gè)參數(shù)值糊秆,如果是用的是全部小寫的武福,只要是不沖突,則可認(rèn)為是準(zhǔn)確的參數(shù)并且表達(dá)了按價(jià)格降序排列這個(gè)語意痘番。常用公共參數(shù)如下:
params | 類型 | 是否必須 | 描述 |
---|---|---|---|
keyword | String | 否 | 用于檢索艘儒,不傳或者傳空,表示默認(rèn)夫偶,默認(rèn)不檢索該關(guān)鍵字 |
sort | String | 否 | 用于對列表排序,不傳則表示默認(rèn)觉增,默認(rèn)按配置順序兵拢,asc升序,desc降序 |
page | int | 否 | 用于分頁描述逾礁,不傳則表示默認(rèn)说铃,默認(rèn)是第1頁 |
pageSize | int | 否 | 表示該頁顯示的條數(shù),不傳則表示默認(rèn)嘹履,默認(rèn)為20條 |
個(gè)性參數(shù)
個(gè)性參數(shù)就是除了公共參數(shù)之外的腻扇,看能否考慮統(tǒng)一用JSON將公共參數(shù)和個(gè)性參數(shù)濃縮成一個(gè)參數(shù),把想要表達(dá)的參數(shù)通過json中的key-value形式傳遞砾嫉。例如:https://api.xxx.com/both/v1/search/products?params={"extra":"你想填什么呢","token":"token_523523523","data":{"uid":"23523523523523"}} 或者考慮與業(yè)務(wù)相關(guān)的參數(shù)就用json形式包裝幼苛,而與業(yè)務(wù)無關(guān)的個(gè)性參數(shù)就還是用傳統(tǒng)的方式另立一個(gè)參數(shù)。例如:https://api.xxx.com/both/v1/search/products?limit=10&offset=10¶ms={"keyword":"方便面","sort":"des"}
通過商議將個(gè)性參數(shù)統(tǒng)一按原始的URL傳參形式傳遞焕刮,不考慮上面所說的那種方式舶沿。
公共響應(yīng)頭
Content-Type:application/json; charset=utf-8
Status:200 OK
其中狀態(tài)碼要與公共響應(yīng)體里的json中的code字段一樣墙杯。
公共響應(yīng)體
默認(rèn)會有以下字段,不需要全部都有括荡。
{
"message": "居然被你查詢成功了",
"code": 200,
"page": 0,
"pageSize": 20,
"first": "https://...",
"next": "https://...",
"previous": "https://...",
"last": "https://...",
"data": {
"uid": "6565656565665"
}
}
key | 類型 | 是否必須 | 描述 |
---|---|---|---|
message | String | 是 | 返回給接口調(diào)用者的描述高镐,有可能用于顯示到界面上,需要進(jìn)行國際化處理 |
code | int | 是 | 這個(gè)與請求頭中的狀態(tài)碼一致畸冲,是為了滿足部分開發(fā)者的習(xí)慣 |
page | int | 否 | 分頁請求中請求的當(dāng)前頁的頁碼 |
pageSize | int | 否 | 分頁請求中一頁的個(gè)數(shù)嫉髓,默認(rèn)為20 |
first | String | 否 | 分頁請求中第一頁的url ,如果沒有則返回空字符串 |
next | String | 否 | 分頁請求中下一頁的url邑闲,如果沒有則返回空字符串 |
previous | String | 否 | 分頁請求中上一頁的url算行,如果沒有則返回空字符串 |
last | String | 否 | 分頁請求中最后一頁的url,如果沒有則返回空字符串 |
data | object | 否 | 當(dāng)前接口的具體數(shù)據(jù)由該json對象承載 |
uid | String | 否 | 對于每一個(gè)資源對象监憎,在返回的時(shí)候纱意,都應(yīng)該返回操作這個(gè)資源對象的唯一碼 |
HTTP動詞表示操作。
常用的HTTP動詞有下面五個(gè)(括號里是對應(yīng)的SQL命令)鲸阔。
- GET(SELECT):從服務(wù)器取出資源(一項(xiàng)或多項(xiàng))偷霉。
例如:GET /zoos:列出所有動物園。 - POST(CREATE):在服務(wù)器新建一個(gè)資源。
例如:POST /zoos:新建一個(gè)動物園踪栋。 - PUT(UPDATE):在服務(wù)器更新資源(客戶端提供改變后的完整資源)昭雌。
例如:PUT /zoos/ID:更新某個(gè)指定動物園的信息(提供該動物園的全部信息)。 - DELETE(DELETE):從服務(wù)器刪除資源硫狞。
例如:DELETE /zoos/ID:刪除某個(gè)動物園。
狀態(tài)碼
作為API的設(shè)計(jì)者晃痴,正確的將API執(zhí)行結(jié)果和失敗原因用清晰簡潔的方式傳達(dá)給客戶程序是十分關(guān)鍵的一步残吩。我們確實(shí)可以在HTTP的相應(yīng)內(nèi)容中描述是否成功,如果出錯(cuò)是因?yàn)槭裁刺群耍欢辏@就意味著用戶需要進(jìn)行內(nèi)容解析,才知道執(zhí)行結(jié)果和錯(cuò)誤原因紧唱。因此活尊,HTTP響應(yīng)代碼可以保證客戶端在第一時(shí)間用最高效的方式獲知 API 運(yùn)行結(jié)果,并采取相應(yīng)動作漏益。下表列出了比較常用的響應(yīng)代碼蛹锰。
常用的http狀態(tài)碼及使用場景:
響應(yīng)代碼 | 代碼含義 |
---|---|
200 | 已創(chuàng)建,請求成功且服務(wù)器已創(chuàng)建了新的資源绰疤。 |
201 | 是否只顯示處于警告狀態(tài)的應(yīng)用實(shí)例铜犬。 |
301 | 重定向 , 請求的網(wǎng)頁已被永久移動到新位置。服務(wù)器返回此響應(yīng)時(shí),會自動將請求者轉(zhuǎn)到新位置翎苫。 |
302 | 重定向 , 請求的網(wǎng)頁臨時(shí)移動到新位置权埠,但求者應(yīng)繼續(xù)使用原有位置來進(jìn)行以后的請求。302 會自動將請求者轉(zhuǎn)到不同的臨時(shí)位置煎谍。 |
304 | 未修改攘蔽,自從上次請求后,請求的網(wǎng)頁未被修改過呐粘。服務(wù)器返回此響應(yīng)時(shí)满俗,不會返回網(wǎng)頁內(nèi)容。 |
400 | 錯(cuò)誤請求 , 服務(wù)器不理解請求的語法作岖。 |
401 | 未授權(quán) , 請求要求進(jìn)行身份驗(yàn)證唆垃。 |
403 | 已禁止 , 服務(wù)器拒絕請求。 |
404 | 未找到 , 服務(wù)器找不到請求的網(wǎng)頁痘儡。 |
405 | 方法禁用 , 禁用請求中所指定的方法辕万。 |
406 | 不接受 , 無法使用請求的內(nèi)容特性來響應(yīng)請求的網(wǎng)頁。 |
408 | 請求超時(shí) , 服務(wù)器等候請求時(shí)超時(shí)沉删。 |
410 | 已刪除 , 如果請求的資源已被永久刪除渐尿,那么,服務(wù)器會返回此響應(yīng)矾瑰。 |
412 | 未滿足前提條件 , 服務(wù)器未滿足請求者在請求中設(shè)置的其中一個(gè)前提條件砖茸。 |
415 | 不支持的媒體類型 , 請求的格式不受請求頁面的支持。 |
500 | 內(nèi)部服務(wù)器錯(cuò)誤殴穴。 |
分頁
分頁適用于GET類型且返回集合數(shù)據(jù)的請求凉夯,根據(jù)如下參數(shù)進(jìn)行分頁操作。分頁返回的數(shù)據(jù)見公共響應(yīng)體采幌。
{
"extra": "你想填什么就填什么",
"page": 0,
"pageSize": 20,
}
params | 類型 | 是否必須 | 描述 |
---|---|---|---|
page | int | 否 | 同上 |
pageSize | int | 否 | 同上 |
錯(cuò)誤/異常處理
- 不要發(fā)生了錯(cuò)誤但給2xx響應(yīng)劲够,客戶端可能會緩存成功的HTTP請求;
- 正確設(shè)置http狀態(tài)碼休傍,不要自定義再沧;
- Response body 提供 1) 錯(cuò)誤的代碼(日志/問題追查);2) 錯(cuò)誤的描述文本(展示給用戶)尊残。
對第三點(diǎn)的實(shí)現(xiàn)稍微多說一點(diǎn):
Java 服務(wù)器端一般用異常表示 RESTful API 的錯(cuò)誤。API 可能拋出兩類異常:業(yè)務(wù)異常和非業(yè)務(wù)異常淤堵。業(yè)務(wù)異常由自己的業(yè)務(wù)代碼拋出寝衫,表示一個(gè)用例的前置條件不滿足、業(yè)務(wù)規(guī)則沖突等拐邪,比如參數(shù)校驗(yàn)不通過慰毅、權(quán)限校驗(yàn)失敗。非業(yè)務(wù)類異常表示不在預(yù)期內(nèi)的問題扎阶,通常由類庫汹胃、框架拋出婶芭,或由于自己的代碼邏輯錯(cuò)誤導(dǎo)致,比如數(shù)據(jù)庫連接失敗着饥、空指針異常犀农、除0錯(cuò)誤等等。
業(yè)務(wù)類異常必須提供2種信息:
- 如果拋出該類異常宰掉,HTTP響應(yīng)狀態(tài)碼應(yīng)該設(shè)成什么呵哨;
- 異常的文本描述;
錯(cuò)誤描述
{
"message": "特么的又錯(cuò)了",
"code": 500,
"document": "https://developer.xxx.com/v1/errors/500",
"exception": [
{
"code": "NullValue",
"target": "PhoneNumber",
"message": "Phone number must not be null"
},
{
"code": "NullValue",
"target": "LastName",
"message": "Last name must not be null"
},
{
"code": "MalformedValue",
"target": "Address",
"message": "Address is not valid"
}
]
}
錯(cuò)誤請求頭
{
"date": "Mon, 08 Jan 2018 03:07:08 GMT",
"server": "nginx/1.10.3 (Ubuntu)",
"connection": "keep-alive",
"content-length": "237",
"content-type": "application/json"
}
錯(cuò)誤狀態(tài)碼(非200)
通過分析發(fā)現(xiàn)轨奄,接口的錯(cuò)誤無非調(diào)用端傳遞給后臺的信息與預(yù)期不符孟害,其中包括公共參數(shù)和個(gè)性參數(shù)不符,不符包括缺失和內(nèi)容錯(cuò)誤(或格式錯(cuò)誤等)兩種挪拟,還有是部分特殊業(yè)務(wù)的特殊性質(zhì)造成非正常結(jié)果挨务,如:重復(fù)申請、重復(fù)簽到等玉组。經(jīng)商議決定將錯(cuò)誤碼分為四大類:
錯(cuò)誤碼 | 類型 | 描述 | 舉例 |
---|---|---|---|
XXX | int | 用于描述缺少參數(shù)谎柄,同時(shí)message做出相應(yīng)的輔助描述,告訴調(diào)用者到底是缺少哪個(gè)參數(shù)球切,這些message只有調(diào)用者看得到谷誓,用戶看不到 | 需要a、b吨凑、c三個(gè)參數(shù)捍歪,結(jié)果只收到a和b參數(shù),或者收到c參數(shù)鸵钝,但c參數(shù)為空字符串糙臼,且c參數(shù)又是必傳的,因此可返回該錯(cuò)誤碼恩商,同時(shí)messgae中提示:缺少c參數(shù)变逃,或者c參數(shù)不能為空 |
XXX | int | 用于描述有參數(shù)但參數(shù)錯(cuò)誤,可能是內(nèi)容錯(cuò)誤或格式錯(cuò)誤怠堪,同時(shí)message做出相應(yīng)的輔助描述揽乱,告訴調(diào)用者到底是哪個(gè)參數(shù)錯(cuò)誤,這些message只有調(diào)用者看得到粟矿,用戶看不到 | 需要傳a參數(shù)為String類型的11位手機(jī)號碼凰棉,結(jié)果收到的是long類型,或只有10位的String陌粹,則可返回該錯(cuò)誤碼撒犀,同時(shí)message提示a參數(shù)錯(cuò)誤 |
XXX | int | 描述某些特定業(yè)務(wù)場景,比如重復(fù)申請、重復(fù)簽到等或舞,每一個(gè)場景對應(yīng)一個(gè)錯(cuò)誤碼荆姆,同時(shí)message會提示相應(yīng)錯(cuò)誤場景,這些message會給用戶看到的 | 比如重復(fù)申請注冊獎(jiǎng)勵(lì)映凳,返回特定碼胆筒,前端做出相應(yīng)顯示,或者跳轉(zhuǎn)魏宽,或者隱藏即可 |
XXX | int | 描述某些公共功能腐泻,調(diào)用者會做出相應(yīng)公共處理 | 比如token失效,直接跳轉(zhuǎn)到登錄界面 |
以上友好的message提示方便了我們队询,同時(shí)也方便了非法調(diào)用者派桩,為阻礙非法調(diào)用,決定設(shè)置一個(gè)開關(guān)蚌斩,該開關(guān)是系統(tǒng)自帶的铆惑,根據(jù)編譯環(huán)境變更,在調(diào)試階段就用以上友好提示送膳,在正式部署上線后就改成模糊提示员魏。
url失效
隨著系統(tǒng)發(fā)展,總有一些API失效或者遷移叠聋,對失效的API撕阎,返回404 not found 或 410 gone;對遷移的API碌补,返回 301 重定向虏束。
對于后臺文檔的要求
文檔要求描述詳盡,盡可能的引導(dǎo)接口使用者理解接口設(shè)計(jì)厦章,這樣才能減少接口的改動镇匀,又能適應(yīng)多變的業(yè)務(wù)。
容錯(cuò)性(健壯性)
考慮到如果測試或者運(yùn)營中有變動袜啃,要求每一個(gè)Web頁面得有容錯(cuò)機(jī)制汗侵,比如關(guān)停該功能,則web必須的有相應(yīng)的頁面展示群发。
國際化
此處的國際化是指語言的國際化晰韵,因此前后端都要考慮在界面的文字提示上要做國際化處理,暫時(shí)我們只做4種文字的國際化:中文(簡體)熟妓、英文雪猪、日文和韓文,經(jīng)商議滑蚯,通過兩方面來傳遞國際化信息:
- 專門的locale設(shè)置接口
- 請求頭中多一個(gè)locale字段
由于有兩個(gè)入口設(shè)置語言,因此有優(yōu)先級處理,請求頭中l(wèi)ocale字段優(yōu)先級大于locale設(shè)置接口告材,兩者不傳坤次,默認(rèn)都表示簡體中文。locale接口默認(rèn)為簡體中文斥赋,如果有設(shè)置其他語言缰猴,則為其他語言,請求頭里如果沒有l(wèi)ocale字段疤剑,則依據(jù)locale接口滑绒,如果請求頭里帶了locale字段,則依據(jù)請求頭為準(zhǔn)隘膘。