天天看點

restful api接口規範_OpenAPI 标準規範

點選上方 IT牧場 ,選擇 置頂或者星标

技術幹貨每日送達!

restful api接口規範_OpenAPI 标準規範

什麼是API規範

API 是子產品或者子系統之間互動的接口定義。好的系統架構離不開好的 API 設計,而一個設計不夠完善的 API 則注定會導緻系統的後續發展和維護非常困難。在關鍵環節制定明确的API規範有助于 Service 對内提高産品間互通的效率,對外提供一緻的使用體驗,也有助于更好地被內建。

對于API規範,比較知名的是 OpenAPI Specfication[1] 和 Google API Design Guide[2]。前者針對 RESTful API 設計在細節層面給出了非常具體的規定,已經成為 RESTful API 設計領域的事實标準,而後者則主要從雲廠商的角度提出許多最佳實踐性質的規範與建議,這些原則不僅僅适用于 RESTful API,也适合其他類型API設計。

雖然RESTful設計風格曝光率很高,但并不是所有雲服務商都選擇了完全遵循RESTful,例如AWS和 阿裡雲[3] RPC 風格反而占了大多數,Google和Azure則RESTful居多。

RESTful API的優勢是HTTP具備更好的易用性,讓異構系統更容易內建,且開發執行效率比較高,面向資源要求也比較高。而RPC API可以使用更廣泛的架構和方案,技術層面更底層也更為靈活,設計起來相對簡單,掌握起來有一定門檻,架構上更加複雜。RESTful 與 RPC 模式對比如下:

RESTful API RPC API
是否有統一規範 HTTP
面向資源 不确定
性能
通用性
複雜度

如果強制統一風格,有些适合 RESTful 風格的服務非要使用RPC的話,看起來就會比較醜陋,如果隻是一個過程化的服務調用,往 RESTful 資源化設計方向去靠會比較困難。但如果不強制使用統一風格,會造成針對API的體系化支援會更加複雜,例如為相容兩種風格SDK的自動化支援需要兩套代碼。

選擇API風格時要考慮幾個問題:

  • 選擇支援哪種風格,才能更好地展現業務特性,讓客戶操作起來更加友善;
  • 設計API時能否面向資源設計,相應的工程人員是否具備做這種設計的能力;
  • 針對這種風格工具鍊的支援是否到位,投入産出比如何;
  • 業界流行的趨勢如何,是否需要考慮與其他系統體系的互操作。

使用者使用API來通路 Service,本質上是想通過對某種資源執行特定的操作來完成一個業務動作。對于資源有兩個關鍵點:一是要有統一的資源模型;二是要明确資源關系。統一的資源模型對 Service 的幫助是巨大的:

  • 它可以使API具有更清晰的結構,幫助使用者了解;
  • 它可以幫助對比API與背景實體關系模型,更容易提供更完整的API服務;
  • 它可以使産品協作更加順暢,對資源的操作也更加規範化;
  • 它可以使雲服務底層平台實作起來更統一、更友善;
  • 它可以使圍繞API的生态內建起來更加簡單、高效。

确定了設計模式和資源模型後,就需要考慮 API的設計細節了,諸如API名稱、參數名、屬性名稱、資料格式、錯誤碼之類的資訊。除此之外,還要考慮以下一些問題:

  • 在API命名的時候,遵循什麼樣的範式來確定大體風格相似?動詞、名詞、介詞如何組合才能保持API風格看起來比較統一,降低了解成本?
  • 對于類似的操作,有沒有使用規範?有哪些公共的标準詞彙使得同類型的操作可以比較容易了解,避免使用晦澀奇怪的詞彙(例如讀操作,Read/Query/Describe/List/Get中都在什麼場合使用什麼動詞)?
  • 被廣泛使用的參數如何盡可能保持一緻,避免不同産品的表達混亂的情況(例如分頁參數用PageNumber還是PageNum)?
  • 對于常用的場景,例如幂等、分頁、異步API的設計有沒有統一的規範,避免使用體驗不一緻?
  • 錯誤碼應該怎麼設計?公共錯誤碼怎麼統一,業務錯誤碼怎麼表達?

上述問題都是實際研發過程中要注意的,要全部羅列的話遠不止這些。API的用詞描述是 Service 展現給外部使用者的第一印象,絕非随意寫就。對人員有一定規模,内部有多條産品線的組織來說,如何協調組織的各個部分對外具有統一的體驗是個很大挑戰。

Service 在管理API時應該考慮一些具體的規範,對命名規則、标準詞彙、最佳實踐模式、錯誤碼等資訊都有明确的規定,同時用系統化、平台化的手段來管理API,確定不走偏。設計風格不是雲服務API設計中緻命的問題,但是它關乎雲服務外表形象,不可不察。

API是後端服務的外部表達,是服務就有可能出現問題,無論這個問題是可預期的還是不可預期的。如果隻考慮功能本身功能特性,而忽視對異常情況的設計,當問題出現的時候業務本身可能無法感覺造成服務異常,更重要的是站在客戶角度去看,不能有效擷取錯誤原因是非常痛苦的,很多時候隻能束手無策,降低雲服務提供商的整體口碑,甚至損害營收。

OpenAPI規範

本規範基于 RESTful 風格的架構設計準則,廣泛參考 GitHub、Azure、Google API Design Guide、騰訊雲、阿裡雲等公開資料,兼顧現有實際情況和未來發展做一個概括性記錄總結。

一、協定

API 與使用者的通信協定,總是使用 HTTPS 協定。這個和 RESTful API 本身沒有很大的關系,但是對于增加網站的安全是非常重要的。特别如果你提供的是公開 API,使用者的資訊洩露或者被攻擊會嚴重影響網站的信譽。

二、版本(Version)

關于版本的設計有3種形式:

  1. 将 API 的版本号放入 URL 中,如:

    http://api.example.com/v1

    ,這樣友善和直覺;
  2. 将版本号記錄在 url query中,如:

    http://api.example.com?param1=val&version=1.0

    中的 version 參數。
  3. 将版本号放在 HTTP 頭資訊中,基于的準則是:不同的版本,可以了解成同一種資源的不同形式,是以應該采用同一個URL。如:

    Accept: application/json; version=1.0

    ,可以參考Github API Design[4]和 Versioning REST Services[5];

根據現有的實際情況,如果是為了相容已存在的服務接口,可以采用對應的形式。如果是新建構的體系結構,建議采用第三種。

三、Schema

URI的格式定義如下:

URI = scheme "://" authority "/" path \[ "?" query \] \[ "#" fragment \]

URL 是 URI 的一個子集(一種具體實作),對于 REST API 來說一個資源一般對應一個唯一的 URI(URL)。在 URL 的設計中,我們會遵循一些規則,使接口看起透明易讀,友善使用者調用。

"/"分隔符一般用來對資源層級的劃分。對于 RESTful API 來說,"/"隻是一個分隔符,并無其他含義。為了避免混淆,"/"不應該出現在URL的末尾。

URL 中盡量使用連字元"-"代替下劃線"_"的使用。 連字元"-"一般用來分割 URL 中出現的字元串(單詞),來提高 URL 的可讀性,例如:

http://api.example.restapi.org/blogs/mark-masse/entries/this-is-my-first-post

。使用下劃線"_"來分割字元串(單詞)可能會和連結的樣式沖突重疊,而影響閱讀性。但實際上,"-"和"_"對URL 中字元串的分割語意上還是有些差異的:"-"分割的字元串(單詞)一般各自都具有獨立的含義,可參見上面的例子。而"_"一般用于對一個整體含義的字元串做了層級的分割,友善閱讀,例如你想在 URL 中展現一個 IP 位址的資訊:210_110_25_88 . (歡迎關注:朱小厮的部落格)

URL應該統一使用小寫字母。

URL中不要包含檔案(腳本)的擴充名。例如

.json

之内的就不要出現了,對于接口來說沒有任何實際的意義。如果是想對傳回的資料内容格式标示的話,通過 HTTP Header 中的 Content-Type 字段更好一些。

對于響應傳回的格式,JSON 因為它的可讀性、緊湊性以及多種語言支援等優點,成為了 HTTP API 最常用的傳回格式。是以,最好采用 JSON 作為傳回内容的格式。如果使用者需要其他格式,比如

xml

,應該在請求頭部

Accept

中指定。對于不支援的格式,服務端需要傳回正确的

status code

,并給出詳細的說明。

JSON中的所有字段都應該用小寫的蛇形命名形式,而不是采用駝峰命名。

四、以資源為中心的 URL 設計

資源是

Restful API

的核心元素,所有的操作都是針對特定資源進行的。而資源就是

URL

(Uniform Resoure Locator)表示的,是以簡潔、清晰、結構化的 URL 設計是至關重要的。Github 可以說是這方面的典範,下面我們就拿

repository

來說明:

我們可以看到幾個特性:

  • 資源分為單個文檔和集合,盡量使用複數來表示資源,單個資源通過添加 id 或者 name 等來表示
  • 一個資源可以有多個不同的 URL
  • 資源可以嵌套,通過類似目錄路徑的方式來表示,以展現它們之間的關系

最常見的一種設計錯誤,就是URL包含動詞。 因為"資源"表示一種實體,是以應該是名詞,URL 不應該有動詞,動詞應該放在 HTTP Method (參考下一條)中。舉例來說,某個 URL 是

/users/show/1

,其中

show

是動詞,這個 URL 就設計錯了,正确的寫法應該是

/users/1

,然後用 HTTP GET 方法表示 show。

如果某些動作是HTTP 動詞表示不了的,你可以把動作看成是一種資源。比如網上彙款,從賬戶1向賬戶2彙款500元,錯誤的 URL 是:

正确的寫法是把動詞 transfer 改成transaction,資源不能是動詞,但是可以是一種服務:

五、正确使用 HTTP Method

有了資源的 URI 設計,所有針對資源的操作都是使用 HTTP 方法指定的。比較常用的 HTTP/1.1 動詞有下面5個:

  • GET:從伺服器取出資源(一項或多項)。
  • POST:在伺服器建立一個資源。
  • PUT:在伺服器更新資源(用戶端提供改變後的完整資源)。
  • PATCH:在伺服器更新資源(更新資源的部分屬性)。
  • DELETE:從伺服器删除資源。

還有4個不常用的 HTTP/1.1 動詞:

  • HEAD:隻擷取某個資源的頭部資訊。比如隻想了解某個檔案的大小,某個資源的修改日期等
  • OPTIONS:擷取資訊,關于資源的哪些屬性是用戶端可以改變的。
  • TRACE:追蹤路徑。不建議使用。
  • CONNECT:要求用隧道協定連接配接代理。不建議使用。

舉例:

這裡順帶探讨一下,HTTP 協定涉及到的一種重要性質:幂等性(Idempotence)。在 HTTP/1.1 規範中幂等性的定義是:

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 方法的幂等性是指一次和多次請求某一個資源應該具有同樣的副作用。幂等性屬于語義範疇,正如編譯器隻能幫助檢查文法錯誤一樣,HTTP 規範也沒有辦法通過消息格式等文法手段來定義它,這可能是它不太受到重視的原因之一。但實際上,幂等性是分布式系統設計中十分重要的概念,而 HTTP 的分布式本質也決定了它在 HTTP 中具有重要地位。

安全方法是指不修改資源的 HTTP 方法。譬如,當使用 GET 或者 HEAD 作為資源 URL,都必須不去改變資源。然而,這并不全準确。意思是:它不改變資源的表示形式。對于安全方法,它仍然可能改變伺服器上的内容或資源,但這必須不導緻不同的表現形式。

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

實際上接口的幂等或者安全與否取決于接口的實作,隻是 HTTP Method 語義上我們約定俗成地認為實作的過程會參照上表所示。對于幂等的接口,用戶端就可以放心地多次調用,網關層面也可以重試。

六、狀态碼 (Status Code)

HTTP 應答中,需要帶一個很重要的字段:

status code

。它說明了請求的大緻情況,是否正常完成、需要進一步處理、出現了什麼錯誤,對于用戶端非常重要。狀态碼都是三位的整數,大概分成了幾個區間:

  • 2XX

    :請求正常處理并傳回
  • 3XX

    :重定向,請求的資源位置發生變化
  • 4XX

    :用戶端發送的請求有錯誤
  • 5XX

    :伺服器端錯誤

在 HTTP API 設計中,經常用到的狀态碼以及它們的意義如下表:

Status Code 語義 說明
200 OK 請求已成功
201 Created 請求已完成,并導緻了一個或者多個資源被建立,最常用在 POST 建立資源的時候
202 Accepted 請求已經接收并開始處理,但是處理還沒有完成。一般用在異步處理的情況,響應 body 中應該告訴用戶端去哪裡檢視任務的狀态
204 No Content 請求已經處理完成,但是沒有資訊要傳回,經常用在 PUT 更新資源的時候(用戶端提供資源的所有屬性,是以不需要服務端傳回)。如果有重要的 metadata,可以放到頭部傳回
301 Moved Permanently 請求的資源已經永久性地移動到另外一個地方,後續所有的請求都應該直接通路新位址。服務端會把新位址寫在

Location

頭部字段,友善用戶端使用。允許用戶端把 POST 請求修改為 GET。
302 Moved Temporarily 臨時重定向
304 Not Modified 請求的資源和之前的版本一樣,沒有發生改變。用來緩存資源,和條件性請求(conditional request)一起出現
307 Temporary Redirect 目标資源暫時性地移動到新的位址,用戶端需要去新位址進行操作,但是 不能 修改請求的方法。
308 Permanent Redirect 和 301 類似,除了用戶端 不能 修改原請求的方法
400 Bad Request 1.語義有誤,目前請求無法被伺服器了解; 2. 請求參數有誤。
401 Unauthorized 目前請求需要身份驗證。
403 Forbidden 伺服器已經了解請求,但是拒絕執行它。與401響應不同的是,身份驗證并不能提供任何幫助,而且這個請求也不應該被重複送出。如果這不是一個 HEAD 請求,而且伺服器希望能夠講清楚為何請求不能被執行,那麼就應該在實體内描述拒絕的原因。當然伺服器也可以傳回一個404響應,假如它不希望讓用戶端獲得任何資訊。
404 Not Found 請求失敗,請求所希望得到的資源未被在伺服器上發現。
405 Method Not Allowed 請求行中指定的請求方法不能被用于請求相應的資源。該響應必須傳回一個Allow 頭資訊用以表示出目前資源能夠接受的請求方法的清單。鑒于 PUT,DELETE 方法會對伺服器上的資源進行寫操作,因而絕大部分的網頁伺服器都不支援或者在預設配置下不允許上述請求方法,對于此類請求均會傳回405錯誤。
406 Not Acceptable 請求的資源的内容特性無法滿足請求頭中的條件,因而無法生成響應實體。
409 Conflict 由于和被請求的資源的目前狀态之間存在沖突,請求無法完成。
429 Too Many Requests 資源配額不足或達到速率限制。
499 Client Closed Request 請求被用戶端取消。
500 Internal Server Error 伺服器内部錯誤
501 Not Implemented 伺服器不支援目前請求所需要的某個功能。當伺服器無法識别請求的方法,并且無法支援其對任何資源的請求。
502 Bad Gateway 作為網關或者代理工作的伺服器嘗試執行請求時,從上遊伺服器接收到無效的響應。
503 Service Unavailable 由于臨時的伺服器維護或者過載,伺服器目前無法處理請求。這個狀況是臨時的,并且将在一段時間以後恢複。
504 Gateway Timeout 作為網關或者代理工作的伺服器嘗試執行請求時,未能及時從上遊伺服器(URI辨別出的伺服器,例如HTTP、FTP、LDAP)或者輔助伺服器(例如DNS)收到響應。
505 HTTP Version Not Supported 伺服器不支援,或者拒絕支援在請求中使用的 HTTP 版本。

上面這些狀态碼覆寫了 API 設計中大部分的情況,如果對某個狀态碼不清楚或者希望檢視更完整的清單,可以參考 HTTP Status Code[6] 、維基百科-狀态碼[7]或者 RFC7231 Response Status Codes[8] 的内容。

七、錯誤處理(Error Handling)

如果出錯,應該在 response body 中通過

message

給出明确的錯誤資訊(一般來說,傳回的資訊中将 message 作為鍵名,出錯詳情作為鍵值即可)。比如用戶端發送的請求有錯誤,一般會傳回

4XX Bad Request

結果。這個結果很模糊,給出錯誤

message

的話,能更好地讓用戶端知道具體哪裡有問題,進行快速修改。

錯誤詳情應該可以幫助使用者輕松快捷地了解和解決API 錯誤。通常,在編寫錯誤詳情時請考慮以下準則:

  • 不要假設使用者是您 API 的專家使用者。使用者可能是用戶端開發人員、操作人員、IT 人員或應用的最終使用者。
  • 不要假設使用者了解有關服務實作的任何資訊,或者熟悉錯誤的上下文(例如日志分析)。
  • 如果可能,應建構錯誤詳情,以便技術使用者(但不一定是 API 開發人員)可以響應錯誤并改正。
  • 確定錯誤詳情内容簡潔。如果需要,請提供一個連結,便于有疑問的讀者提問、提供回報或詳細了解錯誤詳情中不友善說明的資訊。此外,可使用詳細資訊字段來提供更多資訊。

八、命名規則

為了能夠長時間在衆多 API 中為開發者提供一緻的體驗,API 使用的所有名稱都應該具有以下特點:

  • 簡單
  • 直覺
  • 一緻

這包括接口、資源、集合、方法和消息的名稱。

由于很多開發者不是以英語為母語,是以這些命名慣例的目标之一是確定大多數開發者可以輕松了解 API。對于方法和資源,我們鼓勵使用簡單、直覺和少量的詞彙來命名。

  • API 名稱 應該 使用正确的美式英語。例如,使用美式英語的 license、color,而非英式英語的 licence、colour。
  • 為了簡化命名, 可以 使用已被廣泛接受的簡寫形式或縮寫。例如,API 優于 Application Programming Interface。
  • 盡量使用直覺、熟悉的術語。例如,如果描述移除(和銷毀)一個資源,則删除優于擦除。
  • 使用相同的名稱或術語命名同樣的概念,包括跨 API 共享的概念。
  • 避免名稱過載。使用不同的名稱命名不同的概念。
  • 避免在 API 的上下文以及更大的 API 生态系統中使用含糊不清且過于籠統的名稱。這些名稱可能導緻對 API 概念的誤解。相反,應選擇能準确描述 API 概念的名稱。這對定義一階 API 元素(例如資源)的名稱尤其重要。沒有要避免使用的名稱的明确清單,因為每個名稱都必須放在其他名稱的上下文中進行評估。執行個體、資訊和服務是過去有問題的名稱的示例。所選擇的名稱應清楚地描述 API 概念(例如:什麼的執行個體?),并将其與其他相關概念區分開(例如:“alert”是指規則、信号還是通知?)。
  • 仔細考慮是否使用可能與常用程式設計語言中的關鍵字相沖突的名稱。您可以使用這些名稱,但在 API 稽核期間可能會觸發額外的審查。是以應謹慎使用。

九、認證和授權(Authentication & Authorization)

一般來說,讓任何人随意通路公開的 API 是不好的做法。驗證和授權是兩件事情:

  • 驗證(Authentication)是為了确定使用者是其申明的身份,比如提供賬戶的密碼。不然的話,任何人僞造成其他身份(比如其他使用者或者管理者)是非常危險的
  • 授權(Authorization)是為了保證使用者有對請求資源特定操作的權限。比如使用者的私人資訊隻能自己能通路,其他人無法看到;有些特殊的操作隻能管理者可以操作,其他使用者有隻讀的權限等等

如果沒有通過驗證(提供的使用者名和密碼不比對,token 不正确等),需要傳回 401 Unauthorized[9]狀态碼,并在 body 中說明具體的錯誤資訊;而沒有被授權通路的資源操作,需要傳回 403 Forbidden[10] 狀态碼,還有詳細的錯誤資訊。

NOTES: 借鑒于 Github,它對某些使用者未被授權通路的資源操作傳回 404 Not Found[11],目的是為了防止私有資源的洩露(比如黑客可以自動化試探使用者的私有資源,傳回 403 的話,就等于告訴黑客使用者有這些私有的資源)。

十、限流(RateLimit)

如果對通路的次數不加控制,很可能會造成 API 被濫用,甚至被 DDOS 攻擊[12]。根據使用者不同的身份對其進行限流,可以防止這些情況,減少伺服器的壓力。

對使用者的請求限流之後,要有方法告訴使用者它的請求使用情況,本文檔推薦使用的三個相關的頭部:

  • X-RateLimit-Limit

    : 使用者每個小時允許發送請求的最大值
  • X-RateLimit-Remaining

    :目前時間視窗剩下的可用請求數目
  • X-RateLimit-Rest

    : 時間視窗重置的時候,到這個時間點可用的請求數量就會變成

    X-RateLimit-Limit

    的值

舉例:

如果允許沒有登入的使用者使用 API(可以讓使用者試用),可以把

X-RateLimit-Limit

的值設定得很小,比如

60

。沒有登入的使用者是按照請求的 IP 來确定的,而登入的使用者按照認證後的資訊來确定身份。

對于超過流量的請求,可以傳回 429 Too many requests[13] 狀态碼,并附帶錯誤資訊。

十一、編寫優秀的文檔

API 最終是給人使用的,不管是公司内部,還是公開的 API 都是一樣。即使我們遵循了上面提到的所有規範,設計的 API 非常優雅,使用者還是不知道怎麼使用我們的 API。最後一步,但非常重要的一步是:為你的 API 編寫優秀的文檔。

對每個請求以及傳回的參數給出說明,最好給出一個詳細而完整地示例,提醒使用者需要注意的地方……反正目标就是使用者可以根據你的文檔就能直接使用 API,而不是要發郵件給你,或者跑到你的座位上問你一堆問題。

參考資料

[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]

維基百科-狀态碼: 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

restful api接口規範_OpenAPI 标準規範

幹貨分享

最近将個人學習筆記整理成冊,使用PDF分享。關注我,回複如下代碼,即可獲得百度盤位址,無套路領取!

•001:《Java并發與高并發解決方案》學習筆記;•002:《深入JVM核心——原理、診斷與優化》學習筆記;•003:《Java面試寶典》•004:《Docker開源書》•005:《Kubernetes開源書》•006:《DDD速成(領域驅動設計速成)》•007:全部•008:加技術群讨論

近期熱文

•LinkedBlockingQueue vs ConcurrentLinkedQueue•解讀Java 8 中為并發而生的 ConcurrentHashMap•Redis性能監控名額彙總•最全的DevOps工具集合,再也不怕選型了!•微服務架構下,解決資料庫跨庫查詢的一些思路•聊聊大廠面試官必問的 MySQL 鎖機制

關注我

restful api接口規範_OpenAPI 标準規範

喜歡就點個"在看"呗^_^