OpenAPI 標(biāo)準(zhǔn)規(guī)范,了解一下?
什么是API規(guī)范
API 是模塊或者子系統(tǒng)之間交互的接口定義。好的系統(tǒng)架構(gòu)離不開(kāi)好的 API 設(shè)計(jì),而一個(gè)設(shè)計(jì)不夠完善的 API 則注定會(huì)導(dǎo)致系統(tǒng)的后續(xù)發(fā)展和維護(hù)非常困難。在關(guān)鍵環(huán)節(jié)制定明確的API規(guī)范有助于 Service 對(duì)內(nèi)提高產(chǎn)品間互通的效率,對(duì)外提供一致的使用體驗(yàn),也有助于更好地被集成。
對(duì)于API規(guī)范,比較知名的是 OpenAPI Specfication[1] 和 Google API Design Guide[2]。前者針對(duì) RESTful API 設(shè)計(jì)在細(xì)節(jié)層面給出了非常具體的規(guī)定,已經(jīng)成為 RESTful API 設(shè)計(jì)領(lǐng)域的事實(shí)標(biāo)準(zhǔn),而后者則主要從云廠(chǎng)商的角度提出許多最佳實(shí)踐性質(zhì)的規(guī)范與建議,這些原則不僅僅適用于 RESTful API,也適合其他類(lèi)型API設(shè)計(jì)。
雖然RESTful設(shè)計(jì)風(fēng)格曝光率很高,但并不是所有云服務(wù)商都選擇了完全遵循RESTful,例如AWS和 阿里云[3] RPC 風(fēng)格反而占了大多數(shù),Google和Azure則RESTful居多。
RESTful API的優(yōu)勢(shì)是HTTP具備更好的易用性,讓異構(gòu)系統(tǒng)更容易集成,且開(kāi)發(fā)執(zhí)行效率比較高,面向資源要求也比較高。而RPC API可以使用更廣泛的框架和方案,技術(shù)層面更底層也更為靈活,設(shè)計(jì)起來(lái)相對(duì)簡(jiǎn)單,掌握起來(lái)有一定門(mén)檻,架構(gòu)上更加復(fù)雜。RESTful 與 RPC 模式對(duì)比如下:
| RESTful API | RPC API | |
|---|---|---|
| 是否有統(tǒng)一規(guī)范 | HTTP | 無(wú) |
| 面向資源 | 是 | 不確定 |
| 性能 | 中 | 高 |
| 通用性 | 高 | 弱 |
| 復(fù)雜度 | 中 | 高 |
如果強(qiáng)制統(tǒng)一風(fēng)格,有些適合 RESTful 風(fēng)格的服務(wù)非要使用RPC的話(huà),看起來(lái)就會(huì)比較丑陋,如果只是一個(gè)過(guò)程化的服務(wù)調(diào)用,往 RESTful 資源化設(shè)計(jì)方向去靠會(huì)比較困難。但如果不強(qiáng)制使用統(tǒng)一風(fēng)格,會(huì)造成針對(duì)API的體系化支持會(huì)更加復(fù)雜,例如為兼容兩種風(fēng)格SDK的自動(dòng)化支持需要兩套代碼。
選擇API風(fēng)格時(shí)要考慮幾個(gè)問(wèn)題:
選擇支持哪種風(fēng)格,才能更好地體現(xiàn)業(yè)務(wù)特性,讓客戶(hù)操作起來(lái)更加方便; 設(shè)計(jì)API時(shí)能否面向資源設(shè)計(jì),相應(yīng)的工程人員是否具備做這種設(shè)計(jì)的能力; 針對(duì)這種風(fēng)格工具鏈的支持是否到位,投入產(chǎn)出比如何; 業(yè)界流行的趨勢(shì)如何,是否需要考慮與其他系統(tǒng)體系的互操作。
用戶(hù)使用API來(lái)訪(fǎng)問(wèn) Service,本質(zhì)上是想通過(guò)對(duì)某種資源執(zhí)行特定的操作來(lái)完成一個(gè)業(yè)務(wù)動(dòng)作。對(duì)于資源有兩個(gè)關(guān)鍵點(diǎn):一是要有統(tǒng)一的資源模型;二是要明確資源關(guān)系。統(tǒng)一的資源模型對(duì) Service 的幫助是巨大的:
它可以使API具有更清晰的結(jié)構(gòu),幫助用戶(hù)理解; 它可以幫助對(duì)比API與后臺(tái)實(shí)體關(guān)系模型,更容易提供更完整的API服務(wù); 它可以使產(chǎn)品協(xié)作更加順暢,對(duì)資源的操作也更加規(guī)范化; 它可以使云服務(wù)底層平臺(tái)實(shí)現(xiàn)起來(lái)更統(tǒng)一、更方便; 它可以使圍繞API的生態(tài)集成起來(lái)更加簡(jiǎn)單、高效。
確定了設(shè)計(jì)模式和資源模型后,就需要考慮 API的設(shè)計(jì)細(xì)節(jié)了,諸如API名稱(chēng)、參數(shù)名、屬性名稱(chēng)、數(shù)據(jù)格式、錯(cuò)誤碼之類(lèi)的信息。除此之外,還要考慮以下一些問(wèn)題:
在API命名的時(shí)候,遵循什么樣的范式來(lái)確保大體風(fēng)格相似?動(dòng)詞、名詞、介詞如何組合才能保持API風(fēng)格看起來(lái)比較統(tǒng)一,降低理解成本? 對(duì)于類(lèi)似的操作,有沒(méi)有使用規(guī)范?有哪些公共的標(biāo)準(zhǔn)詞匯使得同類(lèi)型的操作可以比較容易理解,避免使用晦澀奇怪的詞匯(例如讀操作,Read/Query/Describe/List/Get中都在什么場(chǎng)合使用什么動(dòng)詞)? 被廣泛使用的參數(shù)如何盡可能保持一致,避免不同產(chǎn)品的表達(dá)混亂的情況(例如分頁(yè)參數(shù)用PageNumber還是PageNum)? 對(duì)于常用的場(chǎng)景,例如冪等、分頁(yè)、異步API的設(shè)計(jì)有沒(méi)有統(tǒng)一的規(guī)范,避免使用體驗(yàn)不一致? 錯(cuò)誤碼應(yīng)該怎么設(shè)計(jì)?公共錯(cuò)誤碼怎么統(tǒng)一,業(yè)務(wù)錯(cuò)誤碼怎么表達(dá)?
上述問(wèn)題都是實(shí)際研發(fā)過(guò)程中要注意的,要全部羅列的話(huà)遠(yuǎn)不止這些。API的用詞描述是 Service 展現(xiàn)給外部用戶(hù)的第一印象,絕非隨意寫(xiě)就。對(duì)人員有一定規(guī)模,內(nèi)部有多條產(chǎn)品線(xiàn)的組織來(lái)說(shuō),如何協(xié)調(diào)組織的各個(gè)部分對(duì)外具有統(tǒng)一的體驗(yàn)是個(gè)很大挑戰(zhàn)。
Service 在管理API時(shí)應(yīng)該考慮一些具體的規(guī)范,對(duì)命名規(guī)則、標(biāo)準(zhǔn)詞匯、最佳實(shí)踐模式、錯(cuò)誤碼等信息都有明確的規(guī)定,同時(shí)用系統(tǒng)化、平臺(tái)化的手段來(lái)管理API,確保不走偏。設(shè)計(jì)風(fēng)格不是云服務(wù)API設(shè)計(jì)中致命的問(wèn)題,但是它關(guān)乎云服務(wù)外表形象,不可不察。
API是后端服務(wù)的外部表達(dá),是服務(wù)就有可能出現(xiàn)問(wèn)題,無(wú)論這個(gè)問(wèn)題是可預(yù)期的還是不可預(yù)期的。如果只考慮功能本身功能特性,而忽視對(duì)異常情況的設(shè)計(jì),當(dāng)問(wèn)題出現(xiàn)的時(shí)候業(yè)務(wù)本身可能無(wú)法感知造成服務(wù)異常,更重要的是站在客戶(hù)角度去看,不能有效獲取錯(cuò)誤原因是非常痛苦的,很多時(shí)候只能束手無(wú)策,降低云服務(wù)提供商的整體口碑,甚至損害營(yíng)收。
OpenAPI規(guī)范
本規(guī)范基于 RESTful 風(fēng)格的架構(gòu)設(shè)計(jì)準(zhǔn)則,廣泛參考 GitHub、Azure、Google API Design Guide、騰訊云、阿里云等公開(kāi)資料,兼顧現(xiàn)有實(shí)際情況和未來(lái)發(fā)展做一個(gè)概括性記錄總結(jié)。
一、協(xié)議
API 與用戶(hù)的通信協(xié)議,總是使用 HTTPS 協(xié)議。這個(gè)和 RESTful API 本身沒(méi)有很大的關(guān)系,但是對(duì)于增加網(wǎng)站的安全是非常重要的。特別如果你提供的是公開(kāi) API,用戶(hù)的信息泄露或者被攻擊會(huì)嚴(yán)重影響網(wǎng)站的信譽(yù)。
二、版本(Version)
關(guān)于版本的設(shè)計(jì)有3種形式:
將 API 的版本號(hào)放入 URL 中,如:
http://api.example.com/v1,這樣方便和直觀;將版本號(hào)記錄在 url query中,如:
http://api.example.com?param1=val&version=1.0中的 version 參數(shù)。將版本號(hào)放在 HTTP 頭信息中,基于的準(zhǔn)則是:不同的版本,可以理解成同一種資源的不同形式,所以應(yīng)該采用同一個(gè)URL。如:
Accept: application/json; version=1.0,可以參考Github API Design[4]和 Versioning REST Services[5];
根據(jù)現(xiàn)有的實(shí)際情況,如果是為了兼容已存在的服務(wù)接口,可以采用對(duì)應(yīng)的形式。如果是新構(gòu)建的體系結(jié)構(gòu),建議采用第三種。
三、Schema
URI的格式定義如下:URI = scheme "://" authority "/" path \[ "?" query \] \[ "#" fragment \]
URL 是 URI 的一個(gè)子集(一種具體實(shí)現(xiàn)),對(duì)于 REST API 來(lái)說(shuō)一個(gè)資源一般對(duì)應(yīng)一個(gè)唯一的 URI(URL)。在 URL 的設(shè)計(jì)中,我們會(huì)遵循一些規(guī)則,使接口看起透明易讀,方便使用者調(diào)用。
"/"分隔符一般用來(lái)對(duì)資源層級(jí)的劃分。對(duì)于 RESTful API 來(lái)說(shuō),"/"只是一個(gè)分隔符,并無(wú)其他含義。為了避免混淆,"/"不應(yīng)該出現(xiàn)在URL的末尾。
URL 中盡量使用連字符"-"代替下劃線(xiàn)"_"的使用。 連字符"-"一般用來(lái)分割 URL 中出現(xiàn)的字符串(單詞),來(lái)提高 URL 的可讀性,例如:http://api.example.restapi.org/blogs/mark-masse/entries/this-is-my-first-post。使用下劃線(xiàn)"_"來(lái)分割字符串(單詞)可能會(huì)和鏈接的樣式?jīng)_突重疊,而影響閱讀性。但實(shí)際上,"-"和"_"對(duì)URL 中字符串的分割語(yǔ)意上還是有些差異的:"-"分割的字符串(單詞)一般各自都具有獨(dú)立的含義,可參見(jiàn)上面的例子。而"_"一般用于對(duì)一個(gè)整體含義的字符串做了層級(jí)的分割,方便閱讀,例如你想在 URL 中體現(xiàn)一個(gè) IP 地址的信息:210_110_25_88 . (歡迎關(guān)注:朱小廝的博客)
URL應(yīng)該統(tǒng)一使用小寫(xiě)字母。
URL中不要包含文件(腳本)的擴(kuò)展名。例如 .json 之內(nèi)的就不要出現(xiàn)了,對(duì)于接口來(lái)說(shuō)沒(méi)有任何實(shí)際的意義。如果是想對(duì)返回的數(shù)據(jù)內(nèi)容格式標(biāo)示的話(huà),通過(guò) HTTP Header 中的 Content-Type 字段更好一些。
對(duì)于響應(yīng)返回的格式,JSON 因?yàn)樗目勺x性、緊湊性以及多種語(yǔ)言支持等優(yōu)點(diǎn),成為了 HTTP API 最常用的返回格式。因此,最好采用 JSON 作為返回內(nèi)容的格式。如果用戶(hù)需要其他格式,比如 xml,應(yīng)該在請(qǐng)求頭部 Accept 中指定。對(duì)于不支持的格式,服務(wù)端需要返回正確的 status code,并給出詳細(xì)的說(shuō)明。
JSON中的所有字段都應(yīng)該用小寫(xiě)的蛇形命名形式,而不是采用駝峰命名。
四、以資源為中心的 URL 設(shè)計(jì)
資源是 Restful API 的核心元素,所有的操作都是針對(duì)特定資源進(jìn)行的。而資源就是 URL(Uniform Resoure Locator)表示的,所以簡(jiǎn)潔、清晰、結(jié)構(gòu)化的 URL 設(shè)計(jì)是至關(guān)重要的。Github 可以說(shuō)是這方面的典范,下面我們就拿 repository 來(lái)說(shuō)明:
/users/:username/repos
/users/:org/repos
/repos/:owner/:repo
/repos/:owner/:repo/tags
/repos/:owner/:repo/branches/:branch
我們可以看到幾個(gè)特性:
資源分為單個(gè)文檔和集合,盡量使用復(fù)數(shù)來(lái)表示資源,單個(gè)資源通過(guò)添加 id 或者 name 等來(lái)表示 一個(gè)資源可以有多個(gè)不同的 URL 資源可以嵌套,通過(guò)類(lèi)似目錄路徑的方式來(lái)表示,以體現(xiàn)它們之間的關(guān)系
最常見(jiàn)的一種設(shè)計(jì)錯(cuò)誤,就是URL包含動(dòng)詞。 因?yàn)?資源"表示一種實(shí)體,所以應(yīng)該是名詞,URL 不應(yīng)該有動(dòng)詞,動(dòng)詞應(yīng)該放在 HTTP Method (參考下一條)中。舉例來(lái)說(shuō),某個(gè) URL 是 /users/show/1,其中 show是動(dòng)詞,這個(gè) URL 就設(shè)計(jì)錯(cuò)了,正確的寫(xiě)法應(yīng)該是 /users/1,然后用 HTTP GET 方法表示 show。
如果某些動(dòng)作是HTTP 動(dòng)詞表示不了的,你可以把動(dòng)作看成是一種資源。比如網(wǎng)上匯款,從賬戶(hù)1向賬戶(hù)2匯款500元,錯(cuò)誤的 URL 是:
POST /accounts/1/transfer/500/to/2
正確的寫(xiě)法是把動(dòng)詞 transfer 改成transaction,資源不能是動(dòng)詞,但是可以是一種服務(wù):
POST /transactoin HTTP/1.1
HOST: 127.0.0.1
from=1&to=2&amount=500
五、正確使用 HTTP Method
有了資源的 URI 設(shè)計(jì),所有針對(duì)資源的操作都是使用 HTTP 方法指定的。比較常用的 HTTP/1.1 動(dòng)詞有下面5個(gè):
GET:從服務(wù)器取出資源(一項(xiàng)或多項(xiàng))。 POST:在服務(wù)器新建一個(gè)資源。 PUT:在服務(wù)器更新資源(客戶(hù)端提供改變后的完整資源)。 PATCH:在服務(wù)器更新資源(更新資源的部分屬性)。 DELETE:從服務(wù)器刪除資源。
還有4個(gè)不常用的 HTTP/1.1 動(dòng)詞:
HEAD:只獲取某個(gè)資源的頭部信息。比如只想了解某個(gè)文件的大小,某個(gè)資源的修改日期等 OPTIONS:獲取信息,關(guān)于資源的哪些屬性是客戶(hù)端可以改變的。 TRACE:追蹤路徑。不建議使用。 CONNECT:要求用隧道協(xié)議連接代理。不建議使用。
舉例:
GET /repos/:owner/:repo/issues
GET /repos/:owner/:repo/issues/:number
POST /repos/:owner/:repo/issues
PATCH /repos/:owner/:repo/issues/:number
DELETE /repos/:owner/:repo
這里順帶探討一下,HTTP 協(xié)議涉及到的一種重要性質(zhì):冪等性(Idempotence)。在 HTTP/1.1 規(guī)范中冪等性的定義是:
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
從定義上看,HTTP 方法的冪等性是指一次和多次請(qǐng)求某一個(gè)資源應(yīng)該具有同樣的副作用。冪等性屬于語(yǔ)義范疇,正如編譯器只能幫助檢查語(yǔ)法錯(cuò)誤一樣,HTTP 規(guī)范也沒(méi)有辦法通過(guò)消息格式等語(yǔ)法手段來(lái)定義它,這可能是它不太受到重視的原因之一。但實(shí)際上,冪等性是分布式系統(tǒng)設(shè)計(jì)中十分重要的概念,而 HTTP 的分布式本質(zhì)也決定了它在 HTTP 中具有重要地位。
安全方法是指不修改資源的 HTTP 方法。譬如,當(dāng)使用 GET 或者 HEAD 作為資源 URL,都必須不去改變資源。然而,這并不全準(zhǔn)確。意思是:它不改變資源的表示形式。對(duì)于安全方法,它仍然可能改變服務(wù)器上的內(nèi)容或資源,但這必須不導(dǎo)致不同的表現(xiàn)形式。
| HTTP Method | 冪等 | 安全 | |
|---|---|---|---|
| 1 | OPTIONS | yes | yes |
| 2 | GET | yes | yes |
| 3 | HEAD | yes | yes |
| 4 | PUT | yes | no |
| 5 | POST | no | no |
| 6 | DELETE | yes | no |
| 7 | PATCH | no | no |
實(shí)際上接口的冪等或者安全與否取決于接口的實(shí)現(xiàn),只是 HTTP Method 語(yǔ)義上我們約定俗成地認(rèn)為實(shí)現(xiàn)的過(guò)程會(huì)參照上表所示。對(duì)于冪等的接口,客戶(hù)端就可以放心地多次調(diào)用,網(wǎng)關(guān)層面也可以重試。
六、狀態(tài)碼 (Status Code)
HTTP 應(yīng)答中,需要帶一個(gè)很重要的字段:status code。它說(shuō)明了請(qǐng)求的大致情況,是否正常完成、需要進(jìn)一步處理、出現(xiàn)了什么錯(cuò)誤,對(duì)于客戶(hù)端非常重要。狀態(tài)碼都是三位的整數(shù),大概分成了幾個(gè)區(qū)間:
2XX:請(qǐng)求正常處理并返回3XX:重定向,請(qǐng)求的資源位置發(fā)生變化4XX:客戶(hù)端發(fā)送的請(qǐng)求有錯(cuò)誤5XX:服務(wù)器端錯(cuò)誤
在 HTTP API 設(shè)計(jì)中,經(jīng)常用到的狀態(tài)碼以及它們的意義如下表:
| Status Code | 語(yǔ)義 | 說(shuō)明 |
|---|---|---|
| 200 | OK | 請(qǐng)求已成功 |
| 201 | Created | 請(qǐng)求已完成,并導(dǎo)致了一個(gè)或者多個(gè)資源被創(chuàng)建,最常用在 POST 創(chuàng)建資源的時(shí)候 |
| 202 | Accepted | 請(qǐng)求已經(jīng)接收并開(kāi)始處理,但是處理還沒(méi)有完成。一般用在異步處理的情況,響應(yīng) body 中應(yīng)該告訴客戶(hù)端去哪里查看任務(wù)的狀態(tài) |
| 204 | No Content | 請(qǐng)求已經(jīng)處理完成,但是沒(méi)有信息要返回,經(jīng)常用在 PUT 更新資源的時(shí)候(客戶(hù)端提供資源的所有屬性,因此不需要服務(wù)端返回)。如果有重要的 metadata,可以放到頭部返回 |
| 301 | Moved Permanently | 請(qǐng)求的資源已經(jīng)永久性地移動(dòng)到另外一個(gè)地方,后續(xù)所有的請(qǐng)求都應(yīng)該直接訪(fǎng)問(wèn)新地址。服務(wù)端會(huì)把新地址寫(xiě)在 Location 頭部字段,方便客戶(hù)端使用。允許客戶(hù)端把 POST 請(qǐng)求修改為 GET。 |
| 302 | Moved Temporarily | 臨時(shí)重定向 |
| 304 | Not Modified | 請(qǐng)求的資源和之前的版本一樣,沒(méi)有發(fā)生改變。用來(lái)緩存資源,和條件性請(qǐng)求(conditional request)一起出現(xiàn) |
| 307 | Temporary Redirect | 目標(biāo)資源暫時(shí)性地移動(dòng)到新的地址,客戶(hù)端需要去新地址進(jìn)行操作,但是 不能 修改請(qǐng)求的方法。 |
| 308 | Permanent Redirect | 和 301 類(lèi)似,除了客戶(hù)端 不能 修改原請(qǐng)求的方法 |
| 400 | Bad Request | 1.語(yǔ)義有誤,當(dāng)前請(qǐng)求無(wú)法被服務(wù)器理解; 2. 請(qǐng)求參數(shù)有誤。 |
| 401 | Unauthorized | 當(dāng)前請(qǐng)求需要身份驗(yàn)證。 |
| 403 | Forbidden | 服務(wù)器已經(jīng)理解請(qǐng)求,但是拒絕執(zhí)行它。與401響應(yīng)不同的是,身份驗(yàn)證并不能提供任何幫助,而且這個(gè)請(qǐng)求也不應(yīng)該被重復(fù)提交。如果這不是一個(gè) HEAD 請(qǐng)求,而且服務(wù)器希望能夠講清楚為何請(qǐng)求不能被執(zhí)行,那么就應(yīng)該在實(shí)體內(nèi)描述拒絕的原因。當(dāng)然服務(wù)器也可以返回一個(gè)404響應(yīng),假如它不希望讓客戶(hù)端獲得任何信息。 |
| 404 | Not Found | 請(qǐng)求失敗,請(qǐng)求所希望得到的資源未被在服務(wù)器上發(fā)現(xiàn)。 |
| 405 | Method Not Allowed | 請(qǐng)求行中指定的請(qǐng)求方法不能被用于請(qǐng)求相應(yīng)的資源。該響應(yīng)必須返回一個(gè)Allow 頭信息用以表示出當(dāng)前資源能夠接受的請(qǐng)求方法的列表。鑒于 PUT,DELETE 方法會(huì)對(duì)服務(wù)器上的資源進(jìn)行寫(xiě)操作,因而絕大部分的網(wǎng)頁(yè)服務(wù)器都不支持或者在默認(rèn)配置下不允許上述請(qǐng)求方法,對(duì)于此類(lèi)請(qǐng)求均會(huì)返回405錯(cuò)誤。 |
| 406 | Not Acceptable | 請(qǐng)求的資源的內(nèi)容特性無(wú)法滿(mǎn)足請(qǐng)求頭中的條件,因而無(wú)法生成響應(yīng)實(shí)體。 |
| 409 | Conflict | 由于和被請(qǐng)求的資源的當(dāng)前狀態(tài)之間存在沖突,請(qǐng)求無(wú)法完成。 |
| 429 | Too Many Requests | 資源配額不足或達(dá)到速率限制。 |
| 499 | Client Closed Request | 請(qǐng)求被客戶(hù)端取消。 |
| 500 | Internal Server Error | 服務(wù)器內(nèi)部錯(cuò)誤 |
| 501 | Not Implemented | 服務(wù)器不支持當(dāng)前請(qǐng)求所需要的某個(gè)功能。當(dāng)服務(wù)器無(wú)法識(shí)別請(qǐng)求的方法,并且無(wú)法支持其對(duì)任何資源的請(qǐng)求。 |
| 502 | Bad Gateway | 作為網(wǎng)關(guān)或者代理工作的服務(wù)器嘗試執(zhí)行請(qǐng)求時(shí),從上游服務(wù)器接收到無(wú)效的響應(yīng)。 |
| 503 | Service Unavailable | 由于臨時(shí)的服務(wù)器維護(hù)或者過(guò)載,服務(wù)器當(dāng)前無(wú)法處理請(qǐng)求。這個(gè)狀況是臨時(shí)的,并且將在一段時(shí)間以后恢復(fù)。 |
| 504 | Gateway Timeout | 作為網(wǎng)關(guān)或者代理工作的服務(wù)器嘗試執(zhí)行請(qǐng)求時(shí),未能及時(shí)從上游服務(wù)器(URI標(biāo)識(shí)出的服務(wù)器,例如HTTP、FTP、LDAP)或者輔助服務(wù)器(例如DNS)收到響應(yīng)。 |
| 505 | HTTP Version Not Supported | 服務(wù)器不支持,或者拒絕支持在請(qǐng)求中使用的 HTTP 版本。 |
上面這些狀態(tài)碼覆蓋了 API 設(shè)計(jì)中大部分的情況,如果對(duì)某個(gè)狀態(tài)碼不清楚或者希望查看更完整的列表,可以參考 HTTP Status Code[6] 、維基百科-狀態(tài)碼[7]或者 RFC7231 Response Status Codes[8] 的內(nèi)容。
七、錯(cuò)誤處理(Error Handling)
如果出錯(cuò),應(yīng)該在 response body 中通過(guò) message 給出明確的錯(cuò)誤信息(一般來(lái)說(shuō),返回的信息中將 message 作為鍵名,出錯(cuò)詳情作為鍵值即可)。比如客戶(hù)端發(fā)送的請(qǐng)求有錯(cuò)誤,一般會(huì)返回 4XX Bad Request 結(jié)果。這個(gè)結(jié)果很模糊,給出錯(cuò)誤 message 的話(huà),能更好地讓客戶(hù)端知道具體哪里有問(wèn)題,進(jìn)行快速修改。
{
"message":"錯(cuò)誤詳情"
}
錯(cuò)誤詳情應(yīng)該可以幫助用戶(hù)輕松快捷地理解和解決API 錯(cuò)誤。通常,在編寫(xiě)錯(cuò)誤詳情時(shí)請(qǐng)考慮以下準(zhǔn)則:
不要假設(shè)用戶(hù)是您 API 的專(zhuān)家用戶(hù)。用戶(hù)可能是客戶(hù)端開(kāi)發(fā)人員、操作人員、IT 人員或應(yīng)用的最終用戶(hù)。 不要假設(shè)用戶(hù)了解有關(guān)服務(wù)實(shí)現(xiàn)的任何信息,或者熟悉錯(cuò)誤的上下文(例如日志分析)。 如果可能,應(yīng)構(gòu)建錯(cuò)誤詳情,以便技術(shù)用戶(hù)(但不一定是 API 開(kāi)發(fā)人員)可以響應(yīng)錯(cuò)誤并改正。 確保錯(cuò)誤詳情內(nèi)容簡(jiǎn)潔。如果需要,請(qǐng)?zhí)峁┮粋€(gè)鏈接,便于有疑問(wèn)的讀者提問(wèn)、提供反饋或詳細(xì)了解錯(cuò)誤詳情中不方便說(shuō)明的信息。此外,可使用詳細(xì)信息字段來(lái)提供更多信息。
八、命名規(guī)則
為了能夠長(zhǎng)時(shí)間在眾多 API 中為開(kāi)發(fā)者提供一致的體驗(yàn),API 使用的所有名稱(chēng)都應(yīng)該具有以下特點(diǎn):
簡(jiǎn)單 直觀 一致
這包括接口、資源、集合、方法和消息的名稱(chēng)。
由于很多開(kāi)發(fā)者不是以英語(yǔ)為母語(yǔ),所以這些命名慣例的目標(biāo)之一是確保大多數(shù)開(kāi)發(fā)者可以輕松理解 API。對(duì)于方法和資源,我們鼓勵(lì)使用簡(jiǎn)單、直觀和少量的詞匯來(lái)命名。
API 名稱(chēng) 應(yīng)該 使用正確的美式英語(yǔ)。例如,使用美式英語(yǔ)的 license、color,而非英式英語(yǔ)的 licence、colour。 為了簡(jiǎn)化命名, 可以 使用已被廣泛接受的簡(jiǎn)寫(xiě)形式或縮寫(xiě)。例如,API 優(yōu)于 Application Programming Interface。 盡量使用直觀、熟悉的術(shù)語(yǔ)。例如,如果描述移除(和銷(xiāo)毀)一個(gè)資源,則刪除優(yōu)于擦除。 使用相同的名稱(chēng)或術(shù)語(yǔ)命名同樣的概念,包括跨 API 共享的概念。 避免名稱(chēng)過(guò)載。使用不同的名稱(chēng)命名不同的概念。 避免在 API 的上下文以及更大的 API 生態(tài)系統(tǒng)中使用含糊不清且過(guò)于籠統(tǒng)的名稱(chēng)。這些名稱(chēng)可能導(dǎo)致對(duì) API 概念的誤解。相反,應(yīng)選擇能準(zhǔn)確描述 API 概念的名稱(chēng)。這對(duì)定義一階 API 元素(例如資源)的名稱(chēng)尤其重要。沒(méi)有要避免使用的名稱(chēng)的明確列表,因?yàn)槊總€(gè)名稱(chēng)都必須放在其他名稱(chēng)的上下文中進(jìn)行評(píng)估。實(shí)例、信息和服務(wù)是過(guò)去有問(wèn)題的名稱(chēng)的示例。所選擇的名稱(chēng)應(yīng)清楚地描述 API 概念(例如:什么的實(shí)例?),并將其與其他相關(guān)概念區(qū)分開(kāi)(例如:“alert”是指規(guī)則、信號(hào)還是通知?)。 仔細(xì)考慮是否使用可能與常用編程語(yǔ)言中的關(guān)鍵字相沖突的名稱(chēng)。您可以使用這些名稱(chēng),但在 API 審核期間可能會(huì)觸發(fā)額外的審查。因此應(yīng)謹(jǐn)慎使用。
九、認(rèn)證和授權(quán)(Authentication & Authorization)
一般來(lái)說(shuō),讓任何人隨意訪(fǎng)問(wèn)公開(kāi)的 API 是不好的做法。驗(yàn)證和授權(quán)是兩件事情:
驗(yàn)證(Authentication)是為了確定用戶(hù)是其申明的身份,比如提供賬戶(hù)的密碼。不然的話(huà),任何人偽造成其他身份(比如其他用戶(hù)或者管理員)是非常危險(xiǎn)的 授權(quán)(Authorization)是為了保證用戶(hù)有對(duì)請(qǐng)求資源特定操作的權(quán)限。比如用戶(hù)的私人信息只能自己能訪(fǎng)問(wèn),其他人無(wú)法看到;有些特殊的操作只能管理員可以操作,其他用戶(hù)有只讀的權(quán)限等等
如果沒(méi)有通過(guò)驗(yàn)證(提供的用戶(hù)名和密碼不匹配,token 不正確等),需要返回 401 Unauthorized[9]狀態(tài)碼,并在 body 中說(shuō)明具體的錯(cuò)誤信息;而沒(méi)有被授權(quán)訪(fǎng)問(wèn)的資源操作,需要返回 403 Forbidden[10] 狀態(tài)碼,還有詳細(xì)的錯(cuò)誤信息。
NOTES: 借鑒于 Github,它對(duì)某些用戶(hù)未被授權(quán)訪(fǎng)問(wèn)的資源操作返回 404 Not Found[11],目的是為了防止私有資源的泄露(比如黑客可以自動(dòng)化試探用戶(hù)的私有資源,返回 403 的話(huà),就等于告訴黑客用戶(hù)有這些私有的資源)。
十、限流(RateLimit)
如果對(duì)訪(fǎng)問(wèn)的次數(shù)不加控制,很可能會(huì)造成 API 被濫用,甚至被 DDOS 攻擊[12]。根據(jù)使用者不同的身份對(duì)其進(jìn)行限流,可以防止這些情況,減少服務(wù)器的壓力。
對(duì)用戶(hù)的請(qǐng)求限流之后,要有方法告訴用戶(hù)它的請(qǐng)求使用情況,本文檔推薦使用的三個(gè)相關(guān)的頭部:
X-RateLimit-Limit: 用戶(hù)每個(gè)小時(shí)允許發(fā)送請(qǐng)求的最大值X-RateLimit-Remaining:當(dāng)前時(shí)間窗口剩下的可用請(qǐng)求數(shù)目X-RateLimit-Rest: 時(shí)間窗口重置的時(shí)候,到這個(gè)時(shí)間點(diǎn)可用的請(qǐng)求數(shù)量就會(huì)變成X-RateLimit-Limit的值
舉例:
X-Ratelimit-Limit: 18000
X-Ratelimit-Remaining: 17995
X-Ratelimit-Reset: 1590570990
如果允許沒(méi)有登錄的用戶(hù)使用 API(可以讓用戶(hù)試用),可以把 X-RateLimit-Limit 的值設(shè)置得很小,比如 60。沒(méi)有登錄的用戶(hù)是按照請(qǐng)求的 IP 來(lái)確定的,而登錄的用戶(hù)按照認(rèn)證后的信息來(lái)確定身份。
對(duì)于超過(guò)流量的請(qǐng)求,可以返回 429 Too many requests[13] 狀態(tài)碼,并附帶錯(cuò)誤信息。
十一、編寫(xiě)優(yōu)秀的文檔
API 最終是給人使用的,不管是公司內(nèi)部,還是公開(kāi)的 API 都是一樣。即使我們遵循了上面提到的所有規(guī)范,設(shè)計(jì)的 API 非常優(yōu)雅,用戶(hù)還是不知道怎么使用我們的 API。最后一步,但非常重要的一步是:為你的 API 編寫(xiě)優(yōu)秀的文檔。
對(duì)每個(gè)請(qǐng)求以及返回的參數(shù)給出說(shuō)明,最好給出一個(gè)詳細(xì)而完整地示例,提醒用戶(hù)需要注意的地方……反正目標(biāo)就是用戶(hù)可以根據(jù)你的文檔就能直接使用 API,而不是要發(fā)郵件給你,或者跑到你的座位上問(wèn)你一堆問(wèn)題。
參考資料
OpenAPI Specfication: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
[2]Google API Design Guide: https://cloud.google.com/apis/design
[3]阿里云: https://bytedance.feishu.cn/docs/doccnrP6Ud3YTavonOlxds9lzad#I1tZbK
[4]Github API Design: https://developer.github.com/v3/#current-version
[5]Versioning REST Services: https://www.informit.com/articles/article.aspx?p=1566460
[6]HTTP Status Code: https://httpstatuses.com/
[7]維基百科-狀態(tài)碼: https://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81
[8]RFC7231 Response Status Codes: https://tools.ietf.org/html/rfc7231#section-6
[9]401 Unauthorized: https://httpstatuses.com/401
[10]403 Forbidden: https://httpstatuses.com/403
[11]404 Not Found: https://httpstatuses.com/404
[12]DDOS 攻擊: https://en.wikipedia.org/wiki/Denial-of-service_attack
[13]429 Too many requests: https://httpstatuses.com/429
往期推薦
關(guān)注我回復(fù)「加群」,加入Spring技術(shù)交流群
