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