REST API 設(shè)計(jì)原則
REST API 的設(shè)計(jì)很有講究,我司總結(jié)了一些規(guī)范和原則,詳見 Cisco REST API 規(guī)范,編譯如下:
REST 方法
- GET 方法的響應(yīng)是由所請求URL代表的資源的表示
- GET 方法不會(huì)改變請求URL所代表的資源
- POST 請求在所請求的URL 路徑下創(chuàng)建一個(gè)新的資源以作為葉子節(jié)點(diǎn)
- POST 響應(yīng)體或者為空(響應(yīng)狀態(tài)碼為204), 或者是所創(chuàng)建的資源的表示(響應(yīng)狀態(tài)碼為201)
- PUT 請求一個(gè)URL, 如果沒有相應(yīng)的資源存在, 就會(huì)創(chuàng)建一個(gè)相應(yīng)的新資源
- PUT 請求一個(gè)URL, 如果已經(jīng)有相應(yīng)的資源存在, 就會(huì)以請求體中的內(nèi)容覆蓋這個(gè)資源
- PUT 響應(yīng)體是所請求的URL代表的資源的表示, 包含了這個(gè)請求所作出的修改
- DELETE 請求一個(gè)URL, 會(huì)刪除相應(yīng)的已存在的資源
- DELETE 的響應(yīng)體或者為空(響應(yīng)碼為204) , 或者是資源的表示(響應(yīng)碼為200)
- PATCH 請求一個(gè)URL, 是部分地修改相應(yīng)的資源的狀態(tài), 參見 RFC6902
- PATCH 響應(yīng)返回所請求的URL代表的資源的表示, 包含了這個(gè)請求所作出的修改
URL 路徑
- URL 路徑表示一個(gè)資源, 或一組資源的集合
- URL 路徑的開頭形式一般為 /{service}/{apiclass}/v{version}
- 集合 URL 的最后一段是一個(gè)名詞算數(shù), 描述所包含資源的類型
- 資源 URL 路徑的最后一段的父節(jié)點(diǎn)是復(fù)數(shù)名詞,表示資源集合。
- 資源 URL 路徑的最后一段是其容器內(nèi)資源的唯一標(biāo)識(shí)符。
- URL 路徑各段是字母或者數(shù)字,遵循駝峰命名法的約定(第一個(gè)字符是小寫)
- URL 路徑各段的命名要直觀,明確,簡潔, 既不拖沓, 又一目了然
URL 查詢參數(shù)
- 表示日期/時(shí)間的URL查詢參數(shù)采用 RFC-3339 的 iso-date-time 格式
- 表示持續(xù)時(shí)間的URL查詢參數(shù)采用 RFC-3339 的 duration 格式
- 表示時(shí)間間隔的URL查詢參數(shù)采用 RFC-3339 的 period 格式
- URL查詢參數(shù)在語義上以及在API中其他位置同名的參數(shù)要保持統(tǒng)一
- 如果選擇所查詢資源的特定字段, URL查詢參數(shù)要符合字段命名和標(biāo)準(zhǔn)規(guī)范. 比如: ?fields=subject,body,createTime
- 與分頁檢索有關(guān)的URL查詢參數(shù)符合分頁查詢形式: ?page=1&size=20&sort=username,asc
- URL查詢參數(shù)名稱是字母數(shù)字,并遵循駝峰命名法的約定(第一個(gè)字符是小寫)
- URL查詢參數(shù)名稱應(yīng)該直觀,明確,簡潔。
Resource Representations 資源表示
- 資源的表示通常編碼為 application/json, 除非資源為其他標(biāo)準(zhǔn)的多媒體類型, 比如 png, vcard 等等
- 資源的集合通常編碼為 application/json, 集合以 json 數(shù)組形式給出
- 如果一個(gè)集合支持分頁, 那么這個(gè)集合的表示應(yīng)該包括一些標(biāo)準(zhǔn)的分頁屬性, 比如集合放在 results 數(shù)組中, 加上 start(開始), size(頁長), total(總數(shù))等屬性, 還可以包含一個(gè) _links 對象, 包括 first, prev, next, last, self 這些鏈接作為屬性
- 一個(gè)資源推薦在資源查詢的響應(yīng)中提供一個(gè) url 屬性, 表示這個(gè)資源自己的鏈接
- 一個(gè)資源不推薦包含另一個(gè)服務(wù)所擁有和負(fù)責(zé)的資源, 可以給出一個(gè)資源的鏈接, 使用絕對路徑和規(guī)范的 URL 形式
- 在資源的響應(yīng)體中一般不包括狀態(tài)信息, 以免和本身http status code 發(fā)生語義上的不一致
- 在返回一個(gè) 4xx 或 5xx 的 HTTP 響應(yīng)碼時(shí), 響應(yīng)主體中就包括標(biāo)準(zhǔn)的錯(cuò)誤信息, 比如: errorCode, errorReason, errorMessage等
JSON Attributes
- 屬性名稱直觀,明確,簡潔。
- 屬性名稱是字母數(shù)字,遵循camelCase約定(第一個(gè)字符是小寫)。
- 表示日期/時(shí)間的屬性采用RFC-3339 iso-date-time格式,并具有UTC偏移量。
- 表示持續(xù)時(shí)間的屬性采用RFC-3339持續(xù)時(shí)間格式。
- 表示時(shí)間間隔的屬性采用RFC-3339周期格式。
- 表示二進(jìn)制值的屬性使用JSON本機(jī)布爾類型進(jìn)行編碼。
- 表示數(shù)組的屬性被命名為復(fù)數(shù)名詞。
- 表示非數(shù)組的屬性被命名為單數(shù)名詞。
- 表示其他資源鏈接的屬性以絕對和規(guī)范URL 的形式提供。
- 屬性名稱在各個(gè)地方應(yīng)該在保持統(tǒng)一的語義
- 表示枚舉類型的屬性要具有明確定義的合法值和語義。
- 缺少JSON屬性與顯式賦值為null之間沒有語義上的區(qū)別。
Security
- REST 請求必需使用 OAuth2 之類的協(xié)議進(jìn)行身份驗(yàn)證,授權(quán)
- REST 請求具有關(guān)于訪問所需資源的要有明確的授權(quán)策略。
- 必須驗(yàn)證包含個(gè)人身份信息(PII)的REST請求。
- REST請求不允許用戶之間無意的內(nèi)容或PII泄漏。
- 必須通過安全通道(HTTPS)進(jìn)行身份驗(yàn)證的 REST 請求。
- REST請求不可以在URL中包含身份驗(yàn)證,授權(quán)或 PII 信息。
API Documentation
- API 文檔應(yīng)該由源代碼或注釋自動(dòng)生成, 比如 swagger 之類的
- 自動(dòng)生成的文檔應(yīng)該對于資源和所提供方法提供足夠的描述信息
- 自動(dòng)生成的文檔應(yīng)該對于認(rèn)證,授權(quán)策略及調(diào)用方法提供足夠的描述信息
- 自動(dòng)生成的文檔應(yīng)該對于URL 路徑, 調(diào)用參數(shù)等提供足夠的描述信息
- 自動(dòng)生成的文檔應(yīng)該對于表示資源的 JSON 屬性提供足夠的描述信息
- 自動(dòng)生成的文檔應(yīng)該對于預(yù)計(jì)的錯(cuò)誤觸發(fā)條件和響應(yīng)碼提供足夠的描述信息
API 文檔工具
API 文檔的生成有很多框架和工具, 現(xiàn)在比較流行的有三種:
1) RESTful API Modeling Language (RAML)
顧名思義, 它是一個(gè)RESTful API 的建模語言, 好象UML 類圖那樣, 通過這個(gè)建模語言描述的 raml 文件來定義你的 API 格式, 然后通過工具(raml2html)來生成易讀的HTML 文檔, 你需要手動(dòng)編寫 raml 文件, 然后生成所需文檔.
它已經(jīng)形成了一套規(guī)范和工具, 例如
? API Workbench: 一個(gè)功能完善的IDE, 可用來設(shè)計(jì), 構(gòu)建,測試 RESTful API, 和相應(yīng)文檔生成和分享
? RAML Java Client Generator: 一個(gè)可以基于 RAML 文檔自動(dòng)生成Java 客戶端代碼的工具
? RAML2HTML: 一個(gè)Node.js 工具, 將 RAML 文件轉(zhuǎn)化成易于閱讀的 HTML文檔.
例如以如下 raml 來定義API
#%RAML 1.0
title: Hello world # required title
version: 1
baseUri: http://example.com/{version}
documentation:
- title: Welcome
content: |
Welcome to the Example Documentation. The Example API allows you
to do stuff. See also [example.com](https://www.example.com).
- title: Chapter two
content: |
More content here. Including **bold** text!
/helloworld: # optional resource
description: This is the top level description for /helloworld.
get: # HTTP method declaration
responses: # declare a response
200: # HTTP status code
body: # declare content of response
application/json: # media type
type: | # structural definition of a response (schema or type)
{
"title": "Hello world Response",
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
example: # example how a response looks like
{
"message": "Hello world"
}
/test:
displayName: TEST
get:
description: a sub resource
/{id}:
uriParameters:
id:
type: string
description: account identifier
minLength: 1
maxLength: 10
get:
headers:
Authorization:
type: string
description: Basic authentication header
example: |
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
put:
body:
application/x-www-form-urlencoded:
properties:
name:
description: name on account
type: string
examples:
example1: Naruto Uzumaki
example2: Kevin Renskers
gender:
enum: ["male", "female"]
然后安裝 raml2html
npm i -g raml2html
npm i -g raml2html-markdown-theme
- 執(zhí)行
raml2html api.raml > api.html
生成的 API html 文件如下

詳情參見 https://github.com/raml2html/raml2html
2) Swagger UI
它是一個(gè)更加流行的文檔生成框架, 強(qiáng)調(diào)從代碼中全自動(dòng)生成 API 文檔
這個(gè)框架有三個(gè)主要的組件:
? Swagger 是它的規(guī)范部分, 一套描述 RESTful 服務(wù)的規(guī)則, 類似于 RAML
? Swagger UI 是它的渲染部分, 它就象 RAML2HTML 那樣生成易讀的HTML文檔, 用戶無需用任何客戶端就可基于Swagger 規(guī)范用它自動(dòng)生成的客戶端進(jìn)行API測試
? Springfox 是它的生成部分, 通過Java代碼, SpringMVC 和 Swagger 的注解來自動(dòng)生成API 文檔.
3) Spring REST Docs
這是 Spring 生態(tài)圈, 它基于API 測試來生成 AsciiDoc 文檔, 你也可以自己編寫一些描述性的 AsciiDoc 文檔, 這些 AsciiDoc 文檔可以通過它提供的 maven 插件自動(dòng)生成易讀的 HTML 文檔, 相比前兩者, 它介于手動(dòng)和全自動(dòng)之間, 相當(dāng)于半自動(dòng)的工具.
如果你是一個(gè)新項(xiàng)目, 在設(shè)計(jì)階段就可以采用 RAML 來定義你的 API, 如果是老項(xiàng)目, 采用 Swagger 會(huì)更省力, 當(dāng)然 Spring REST Docs 更加符合測試驅(qū)動(dòng)開發(fā)的理念, 既可以通過測試來自動(dòng)生成文檔, 也可以手動(dòng)添加說明, 推薦使用