Google API設計指南-標準方法

翻譯自 API Design Guide - Standard Methodsnode

此章節定義標準方法 ListGetCreateUpdateDelete。標準方法存在的意義是普遍的 API 中許多 API 方法具備很是類似的語義,經過將這些相似的 API 融合到標準方法中,咱們能夠顯著下降複雜性並提升一致性。以 Google APIs 爲例,超過 70% 是標準方法,這讓它們更加易於學習和使用。git

下表描述瞭如何將它們映射爲 REST 方法,也稱爲 CRUD 方法:github

| 方法 | HTTP 映射 | HTTP 請求體 | HTTP 響應體 |
| - | - | - | - |
| List | GET <集合 URL> | 空 | 資源[1]列表 |
| Get | GET <資源 URL> | 空 | 資源[1] |
| Create | POST <集合 URL> | 資源 | 資源[1] |
| Update | PUT 或 PATCH <資源 URL> | 資源 | 資源[1] |
| Delete | DELETE <資源 URL> | 空 | 空[2] |api

[1] ListGetCreateUpdate方法支持字段掩碼時,返回的資源 可能(may) 只包含部分數據。在某些狀況下,API 平臺會對全部方法原生支持字段掩碼。緩存

[2] 不當即刪除資源(好比經過更新標誌位或會執行時間較長的刪除操做)的 Delete 方法返回的響應 應該(should) 包含長時間運行的操做或被修改的資源。ide

標準方法也 能夠(may) 爲不能在一個 API 調用週期完成的請求返回長期運行的操做post

下面章節詳細描述了每個標準方法。這些例子展現了在 .proto 文件中定義的方法,其中包含用於 HTTP 映射的特殊註釋。你能夠在 Google APIs 項目中找到許多使用標準方法的例子。學習

List

List 方法接收資源名和零個或多個其它參數作爲輸入,返回符合輸入的資源列表。它也一般被用來搜索資源。ui

List 適合取得沒有緩存且大小有限的來自單個集合的數據。對於更普遍的狀況,應該(should) 使用自定義方法google

應該使用自定義的 BatchGet 方法來實現批量獲取(例如接收多個資源 ID而後返回對應的資源),而不是使用 List。但若是已存在可以提供一樣功能的 List 方法,你 能夠(may) 爲此目的重用 List 方法。若是你在使用自定義的 BatchGet 方法,應該(should) 將它映射成 HTTP GET

適用的常見模式:分頁結果排序

適用的命名約定:過濾字段結果字段

HTTP 映射:

  • List 方法 必須(must) 使用 HTTP GET 動詞。

  • 應該(should) 把要列出集合的資源名字放在 URL path 參數中。若是集合名映射到 URL path 中,URL 模版的最後一段(集合 ID必須(must) 是常量。

  • 全部其餘的請求信息字段 必須(shall) 映射到 URL 的 query 參數中。

  • 沒有請求體,API 配置中必定不能(must not) 定義 body

  • 響應體 應該(should) 包含資源列表和可選的元數據。

// 列出指定書架上的全部圖書
rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {
  // List 方法映射爲 HTTP GET
  option (google.api.http) = {
    // `parent` 獲取父資源名,例如 "shelves/shelf1"
    get: "/v1/{parent=shelves/*}/books"
  };
}

message ListBooksRequest {
  // 父資源名稱,例如 "shelves/shelf1".
  string parent = 1;

  // 返回值的最大條數
  int32 page_size = 2;

  // 從上一個 List 請求返回的 next_page_token 值(若是存在)
  string page_token = 3;
}

message ListBooksResponse {
  // 字段名應該匹配方法名中的名詞 "books",根據請求中的 page_size 字段,將會返回最大數量的條目
  repeated Book books = 1;

  // 用於取得下一頁結果的值,沒有時爲空
  string next_page_token = 2;
}

Get

GET 方法接收資源名,零個或多個參數,返回指定的資源。

HTTP 映射:

  • Get 方法 必須(must) 使用 HTTP GET 動詞。

  • 表示資源名的請求信息字段 應該(should) 映射到 URL path 參數中。

  • 全部其餘的請求信息字段 必須(shall) 映射到 URL 的 query 參數中。

  • 沒有請求體,API 配置中必定不能(must not) 定義 body

  • 返回的資源 必須(shall) 填充整個響應體。

// 取得指定的 book
rpc GetBook(GetBookRequest) returns (Book) {
  // Get 映射爲 HTTP GET。資源名映射到 URL 中。沒有請求體
  option (google.api.http) = {
    // 注意 URL 中用於獲取資源名的模板變量,例如 "shelves/shelf1/books/book2"
    get: "/v1/{name=shelves/*/books/*}"
  };
}

message GetBookRequest {
  // 此字段包含被請求資源的名字,例如:"shelves/shelf1/books/book2"
  string name = 1;
}

Create

Create 方法接收一個集合名、零個或多個參數,在指定集合中建立一個新的資源並將其返回。

若是 API 支持建立資源,它 應該(should) 在全部可被建立的資源上具備 Create 方法 。

HTTP 映射:

  • Create 方法 必須(must) 使用 HTTP POST 動詞。

  • 請求消息中 應該(should) 含有名爲 parent 的字段來接收新建資源的父資源名。

  • 全部其餘的請求信息字段 必須(shall) 映射到 URL 的 query 參數中。

  • 請求 能夠(may) 包含名爲 <resource>_id 的字段名來容許調用者選擇一個客戶端分配的 ID。這個字段 必須(must) 映射到 URL query 參數中。

  • 包含資源的請求信息字段 應該(should) 映射到請求體中。若是 Create 方法使用了 HTTP 配置中的 body 字段,那麼 必須(must) 使用 body: "<resource_field>" 這種格式。

  • 返回的資源 必須(shall) 填充到整個響應體。

若是 Create 方法支持客戶端指定資源名,當資源名已存在時請求 應該(should) 失敗(推薦(recommended) 使用 google.rpc.Code.ALREADY_EXISTS)或者服務端分配另外的名字,而且文檔中應該明確指出建立的資源名可能會與傳入的名字不一樣。

rpc CreateBook(CreateBookRequest) returns (Book) {
  // Create 映射爲 HTTP POST,URL path 作爲集合名稱
  // HTTP 請求體中包含資源
  option (google.api.http) = {
    // 經過 `parent` 獲取父資源名,例如 "shelves/1"
    post: "/v1/{parent=shelves/*}/books"
    body: "book"
  };
}

message CreateBookRequest {
  // 將被建立的 book 的父資源名
  string parent = 1;

  // book 使用的 ID
  string book_id = 3;

  // 資源 book 將被建立,字段名應該與方法名中的名詞相匹配
  Book book = 2;
}

rpc CreateShelf(CreateShelfRequest) returns (Shelf) {
  option (google.api.http) = {
    post: "/v1/shelves"
    body: "shelf"
  };
}

message CreateShelfRequest {
  Shelf shelf = 1;
}

Update

Update 方法接收包含資源和零個或多個參數的請求,更新指定的資源和屬性並返回更新後的資源。

可修改的資源屬性 應該(should) 使用 Update 方法來更新,除非屬性中包含資源名或父資源。任何重命名移動資源的操做 必定不要(must not) 經過 Update 執行,必須(shall) 經過自定義方法處理。

HTTP 映射:

  • 標準的 Update 方法 應該(should) 支持資源的部分更新,使用帶有名爲 update_maskFieldMask 字段的 HTTP 動詞 PATCH 來執行操做。

  • 應該(should) 使用自定義方法來實現更高級的 Update 方法,例如追加劇復的字段。

  • 若是 Update 方法僅支持資源的完整更新,則 必須(must) 使用 HTTP 動詞 PUT實現。然而並不鼓勵這樣作,由於當添加新的資源字段時會有後向兼容的問題。

  • 被修改資源的名稱字段 必須(must) 映射到 URL path 參數中。此字段也 能夠(may) 加在資源信息中。

  • 包含資源的請求信息 必須(must) 映射到請求體中。

  • 全部其餘請求信息 必須(must) 映射到 URL query 參數中。

  • 返回響應中的資源信息 必須(must) 是被修改的資源。

若是 API 接收客戶端分配的資源名,那麼服務端 能夠(may) 容許客戶端指定一個不存在的資源名來建立新的資源。不然,Update 方法應該(should) 由於不存在的資源名而失敗。當資源名不存在是惟一錯誤時,應該(should) 使用錯誤碼 NOT_FOUND

即便 API 的 Update 方法可以新建資源,它也 應該(should) 提供 Create 方法。這是由於只有 Update 方法可以新建資源會讓人迷惑。

rpc UpdateBook(UpdateBookRequest) returns (Book) {
  // Update 映射爲 HTTP PATCH。資源名映射到 URL path 參數中
  // 資源包含在 HTTP 請求體中
  option (google.api.http) = {
    // 注意用於獲取待更新 book 的資源名的 URL 模版變量
    patch: "/v1/{book.name=shelves/*/books/*}"
    body: "book"
  };
}

message UpdateBookRequest {
  // 替換服務端上的 book 資源
  Book book = 1;

  // 用於資源更新的掩碼
  // `FieldMask` 的定義請參考 https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask
  FieldMask update_mask = 2;
}

Delete

Delete 方法接收資源名和零個或多個參數,而後刪除或準備刪除指定資源。Delete 方法 應該(should) 返回 google.protobuf.Empty

注意,API 不該該(should not) 依賴 Delete 方法返回的任何信息,由於它不能重複調用。

HTTP 映射:

  • Delete 方法 必須(must) 使用 HTTP DELETE 動詞

  • 表示資源名的請求信息字段 應該(should) 映射到 URL path 參數中

  • 全部其餘的請求信息字段 必須(shall) 映射到 URL 的 query 參數中

  • 沒有請求體,API 配置 必定不要(must not) 定義 body

  • Delete 方法直接刪除資源時,應該(should) 返回空的響應

  • Delete 方法初始化一個長時間的操做時,應該(should) 返回這個操做

  • Delete 方法將資源標記爲被刪除時,應該(should) 返回更新後的資源

Delete 方法的調用在效果上應該是冪等的,但並不須要有相同的返回值。任意次 Delete 請求的結果 應該(should) 是資源被刪除,但只有第一次請求應該返回正確,後續的請求應該返回 google.rpc.Code.NOT_FOUND

rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
  // Delete 映射爲 HTTP DELETE。資源名映射到 URL path 參數中
  // 沒有請求體
  option (google.api.http) = {
    // 注意 URL 模板變量獲取待刪除資源的名稱,例如 "shelves/shelf1/books/book2"
    delete: "/v1/{name=shelves/*/books/*}"
  };
}

message DeleteBookRequest {
  // 待刪除的資源名稱,例如 "shelves/shelf1/books/book2"
  string name = 1;
}

查看其餘章節

相關文章
相關標籤/搜索