本文摘抄至 Google Cloud API 設(shè)計(jì)指南(見附錄1),用于標(biāo)注在實(shí)踐該規(guī)范時(shí)一些關(guān)鍵注重點(diǎn)。(未完待續(xù)...)
簡介
這是互聯(lián)網(wǎng) API 的通用設(shè)計(jì)指南。它自 2014 年起在 Google 內(nèi)部使用,是 Google 在設(shè)計(jì) Cloud API 和其他 Google API 時(shí)遵循的指南。我們在此公開此設(shè)計(jì)指南,目的是為外部開發(fā)者提供信息,使我們所有人都能更輕松地協(xié)同工作。
HTTP 準(zhǔn)則
- HTTP 請求和響應(yīng)主體使用
application/json作為Content-TypeTODO 舉例 - 長請求網(wǎng)址(GET/DELETE)
網(wǎng)址具有實(shí)際長度限制,通常在 2k-8k 之間,當(dāng)使用的 API 網(wǎng)址超過長度限制時(shí),可能會(huì)由于多方原因拒絕此請求。要避開該限制,客戶端應(yīng)設(shè)置Content-Type: application/x-www-form-urlencoded的 POST 請求,且 HTTP 標(biāo)頭為X-HTTP-Method-Override: GETTODO 舉例 -
請求網(wǎng)址符合 REST 模型時(shí),應(yīng)將 HTTP 方法指定為 API 規(guī)范的一部分
安全方法不應(yīng)表示檢索以外的操作(如 GET 和 HEAD),不應(yīng)對客戶端產(chǎn)生任何的副作用。
HTTP 中的冪等性,意味著多個(gè)相同的請求產(chǎn)生的副作用與單個(gè)請求相同(GET/PUT/DELETE)
image.png - 其他詳情查看附錄2
REST
什么是 REST API?
REST(Representational State Transfer) API 是可單獨(dú)尋址的“資源”(API 中的“名詞”)的“集合”。資源通過資源名稱被引用,并通過一組“方法”(也稱為“動(dòng)詞”或“操作”)進(jìn)行控制。
資源
面向資源的 API 通常被構(gòu)建為資源層次結(jié)構(gòu),其中每個(gè)節(jié)點(diǎn)是一個(gè)“簡單資源”或“集合資源”。 為方便起見,它們通常被分別稱為資源和集合。
- 一個(gè)集合包含相同類型的資源列表。 例如,一個(gè)用戶擁有一組聯(lián)系人。
- 資源具有一些狀態(tài)和零個(gè)或多個(gè)子資源。 每個(gè)子資源可以是一個(gè)簡單資源或一個(gè)集合資源。
資源名稱
// 書架上的書
shelves/${shelf1}/books/${book2}
// 資源名
- 必須是復(fù)數(shù)形式的小駝峰(如果沒有合適的復(fù)數(shù)形式,則使用單數(shù)形式)
- 必須使用簡明扼要的英文詞語
- 應(yīng)該避免使用過于籠統(tǒng)的詞語,或?qū)ζ湎薅ê笫褂茫ɡ?rowValues 優(yōu)先于 values),例如:elements/entries/instances/items/objects/resources/types/values
- 資源名需要網(wǎng)址轉(zhuǎn)義(URLEncode)
- 資源名為字符串
- 推薦使用資源名代替資源 ID 來標(biāo)識資源
方法
面向資源的 API 的關(guān)鍵特性是,強(qiáng)調(diào)資源(數(shù)據(jù)模型)甚于資源上執(zhí)行的方法(功能)。典型的面向資源的 API 使用少量方法公開大量資源。方法可以是標(biāo)準(zhǔn)方法或自定義方法。對于本指南,標(biāo)準(zhǔn)方法有:List、Get、Create、Update 和 Delete
示例
Gmail API 服務(wù)實(shí)現(xiàn)了 Gmail API 并公開了大多數(shù) Gmail 功能。它具有以下資源模型:
- API 服務(wù):gmail.googleapis.com
- 用戶集合:users/*。每個(gè)用戶都擁有以下資源。
- 消息集合:users/*/messages/*。
- 線程集合:users/*/threads/*。
- 標(biāo)簽集合:users/*/labels/*。
- 變更歷史記錄集合:users/*/history/*。
- 表示用戶個(gè)人資料的資源:users/*/profile。
- 表示用戶設(shè)置的資源:users/*/settings。
標(biāo)準(zhǔn)方法
標(biāo)準(zhǔn)方法可降低復(fù)雜性并提高一致性
image.png
List(列表)
常用于搜索資源,適用于來自單個(gè)集合的數(shù)據(jù),該集合大小有限且不進(jìn)行緩存
HTTP 映射
- Method: GET
- 響應(yīng)正文應(yīng)該包含資源列表,以及可選元數(shù)據(jù)
- 接收資源名稱的請求消息字段應(yīng)該映射到網(wǎng)址路徑(資源主體標(biāo)識)
- 所有剩余的請求消息字段應(yīng)該映射到網(wǎng)址查詢參數(shù)(query params)
// 分頁查詢場景
GET shelves/${shelf1}/books?page=1&pageSize=10&pageToken={上一頁的標(biāo)識}
{
books: [...],
nextPageToken: "..." // 可缺省
}
// TODO(d): 無分頁場景是否適用本規(guī)則?
常見狀態(tài)碼(HTTP)
- 200 資源獲取成功
- 4xx 一些請求錯(cuò)誤
- TODO
Get(獲?。?/h2>
返回指定資源
HTTP 映射
- Method: GET
- 響應(yīng)正文應(yīng)該包含資源列表,以及可選元數(shù)據(jù)
- 接收資源名稱的請求消息字段應(yīng)該映射到網(wǎng)址路徑(資源主體標(biāo)識)
- 所有剩余的請求消息字段應(yīng)該映射到網(wǎng)址查詢參數(shù)(query params)
GET shelves/${shelf1}/books/${encode('時(shí)間簡史')}?author=zhangsan
// 整個(gè)返回體為 Book 實(shí)例
{
author: 'zhangsan',
content: 'xxx'
}
常見狀態(tài)碼(HTTP)
- 200 資源獲取成功
- 404 找不到資源
- 4xx 一些請求錯(cuò)誤
- TODO
Create(創(chuàng)建)
在指定父資源下創(chuàng)建新資源,并返回新創(chuàng)建的資源。
HTTP 映射
- Method: POST
- 所有剩余的請求消息字段應(yīng)該映射到網(wǎng)址查詢參數(shù)
POST shelves/${shelf1}/books
// 請求正文為即將創(chuàng)建的資源
{
name: 'xxx',
author: 'xxx'
}
// 響應(yīng)正文
{
name: 'xxx',
author: 'xxx'
}
常見狀態(tài)碼(HTTP)
- 200 資源創(chuàng)建成功(對于標(biāo)準(zhǔn)的 RESTful API 來說,創(chuàng)建成功對應(yīng) 201,但 Google 規(guī)范中,標(biāo)準(zhǔn) POST 不再用于更新場景,所以不存在語義上的沖突)
- 4xx 一些請求錯(cuò)誤
- TODO
Update(更新)
用于除了更新資源名或父資源屬性之外,可以改變所有可變資源(重命名或移動(dòng)應(yīng)使用自定義方法)
HTTP 映射(標(biāo)準(zhǔn))
Method: PATCH
- 支持部分資源更新,并設(shè)置更新部分的字段掩碼
- 包含資源的請求消息字段必須映射到請求正文
- 所有剩余的請求消息字段必須映射到網(wǎng)址查詢參數(shù)
- 響應(yīng)消息必須是更新的資源本身
PATCH shelves/${shelf1}/books/${bookName}
// 請求正文
{
book: {
name: 'xxx'
},
updateMask: 'book.name'
}
// 響應(yīng)正文
{
name: 'xxx',
author: 'xxx'
}
HTTP 映射(完整資源更新,不推薦,添加新字段時(shí)會(huì)存在向后兼容問題)
- Method: PUT
- 僅支持完整更新
- 包含資源的請求消息字段必須映射到請求正文
- 所有剩余的請求消息字段必須映射到網(wǎng)址查詢參數(shù)
- 響應(yīng)消息必須是更新的資源本身
PUT shelves/${shelf1}/books/${bookName}
// 請求正文
{
name: 'xxx', // 改變此字段
author: 'xxx' // 不變此字段
}
// 響應(yīng)正文
{
name: 'xxx',
author: 'xxx'
}
常見狀態(tài)碼(HTTP)
- 200 更新成功
- 4xx 一些請求錯(cuò)誤
- TODO
Delete(刪除)
用于刪除或計(jì)劃刪除指定資源,API 不應(yīng)依賴于該方法返回任何信息,因?yàn)椴荒苤貜?fù)調(diào)用。
HTTP 映射(完整資源更新,不推薦,添加新字段時(shí)會(huì)存在向后兼容問題)
- Method: DELETE
- 接收資源名稱的請求消息字段應(yīng)該映射到網(wǎng)址路徑
- 所有剩余的請求消息字段應(yīng)該映射到網(wǎng)址查詢參數(shù)
- 如果 Delete 方法立即移除資源,則應(yīng)該返回空響應(yīng)
- 如果 Delete 方法啟動(dòng)長時(shí)間運(yùn)行的操作,則應(yīng)該返回長時(shí)間運(yùn)行的操作
- 如果 Delete 方法僅將資源標(biāo)記為已刪除,則應(yīng)該返回更新后的資源
DELETE shelves/${shelf1}/books/${bookName}
常見狀態(tài)碼(HTTP)
- 200 刪除成功
- 404 資源不存在
- 4xx 一些請求錯(cuò)誤
- TODO
自定義方法
自定義方法是指 5 個(gè)標(biāo)準(zhǔn)方法之外的 API 方法。這些方法應(yīng)該僅用于標(biāo)準(zhǔn)方法不易表達(dá)的功能。通常情況下,API 設(shè)計(jì)者應(yīng)該盡可能優(yōu)先考慮使用標(biāo)準(zhǔn)方法,而不是自定義方法。標(biāo)準(zhǔn)方法具有大多數(shù)開發(fā)者熟悉的更簡單且定義明確的語義,因此更易于使用且不易出錯(cuò)。另一項(xiàng)優(yōu)勢是 API 平臺更加了解和支持標(biāo)準(zhǔn)方法,例如計(jì)費(fèi)、錯(cuò)誤處理、日志記錄、監(jiān)控。
自定義方法可以與資源、集合或服務(wù)關(guān)聯(lián)。 它可以接受任意請求和返回任意響應(yīng),并且還支持流式請求和響應(yīng)。
https://service.name/v1/some/resource/name:customVerb
- 自定義方法應(yīng)使用 HTTP POST,因?yàn)樵搫?dòng)詞具有更靈活的語義。(作為替代 GET 或 LIST 的方法,可以使用 GET)
- 自定義方法不應(yīng)該使用 HTTP PATCH(根據(jù)具體語義而定)
常用自定義方法

錯(cuò)誤
Google API 的錯(cuò)誤模型由 google.rpc.Status 邏輯定義,該實(shí)例
在發(fā)生 API 錯(cuò)誤時(shí)返回給客戶端
格式(rpc)
package google.rpc;
message Status {
// 客戶端可以輕松處理的簡單錯(cuò)誤代碼
int32 code = 1;
// 面向開發(fā)人員人類可讀的錯(cuò)誤信息,它應(yīng)該解釋錯(cuò)誤,并提供一個(gè)可行的解決方案
string message = 2;
// 一些額外的錯(cuò)誤信息,如重試信息或幫助鏈接
repeated google.protobuf.Any details = 3;
}
格式(http)
// resp headers
Content-Type: application/json
Status: 404
// resp body
{
"message": "NOT FOUND",
"details": "" // 可選
}
單個(gè) API 應(yīng)避免定義其他錯(cuò)誤代碼,因?yàn)殚_發(fā)人員不太可能編寫用于處理大量錯(cuò)誤代碼的邏輯。作為參考,每個(gè) API 調(diào)用平均處理 3 個(gè)錯(cuò)誤代碼意味著大多數(shù)應(yīng)用邏輯僅用于錯(cuò)誤處理,這并不會(huì)帶來良好的開發(fā)者體驗(yàn)。
常見錯(cuò)誤狀態(tài)

命名規(guī)范
大規(guī)則:簡單、直觀、一致
- 采用美式英語(如:使用 license(美) 而非 licence(英))
- 可以使用已被廣泛接受的簡寫
- 盡量使用常用詞匯(如:描述移除和銷毀,刪除優(yōu)于擦除)
- 避免名稱過載。使用不同的名稱命名不同的概念
- 避免過于籠統(tǒng)的命名
- 集合 ID 采用小駝峰復(fù)數(shù)形式(如:members)
設(shè)計(jì)模式
列表分頁
可列表集合應(yīng)該支持分頁,即使結(jié)果通常很小
如果某個(gè) API 從一開始就不支持分頁,稍后再支持它就比較麻煩,因?yàn)樘砑臃猪摃?huì)破壞 API 的行為。 不知道 API 正在使用分頁的客戶端可能會(huì)錯(cuò)誤地認(rèn)為他們收到了完整的結(jié)果,而實(shí)際上只收到了第一頁
跨子集執(zhí)行 List/Search 操作
有時(shí),API 需要讓客戶跨子集執(zhí)行 List/Search 操作。例如,“API 圖書館”有一組書架,每個(gè)書架都有一系列書籍,而客戶希望在所有書架上搜索某一本書。在這種情況下,建議在子集合上使用標(biāo)準(zhǔn) List,并為父集合指定通配符集合 ID "-"。對于“API 圖書館”示例,我們可以使用以下 REST API 請求:
GET https://xxx/v1/shelves/-/books?filter=xxx
枚舉默認(rèn)值:0
每個(gè)枚舉定義必須以 0 值條目開頭,當(dāng)未明確指定枚舉值時(shí),應(yīng)使用該條目。API 必須記錄如何處理 0 值
部分響應(yīng)(與 List/Search 區(qū)別?)
通過特殊字段(如 Google 的 FieldMask)給予過濾響應(yīng)集合內(nèi)容
資源視圖
為了減少網(wǎng)絡(luò)流量,有時(shí)可允許客戶端限制服務(wù)器應(yīng)在其響應(yīng)中返回的資源部分,即返回資源視圖而不是完整的資源表示形式。API 中的資源視圖支持是通過向方法請求添加一個(gè)參數(shù)來實(shí)現(xiàn)的,該參數(shù)允許客戶端指定希望在響應(yīng)中接收的資源視圖

