前後端完全分離之API設計

arccode發表於2015-04-20

背景

API就是開發者使用的介面。我的目標不僅是能用,而且好用, 跨平臺(PC, Android, IOS, etc...)使用; 本文將詳細介紹API的設計及異常處理, 並將異常資訊進行封裝友好地反饋給前端.

上篇文章前後端完全分離初探只是講了些寬泛的概念, 接下來的文章將直接上乾貨, 乾貨的原始碼會掛在github上.

前後端完全分離後, 前端和後端如何互動?

答: 通過雙方協商好的API.

接下來我分享我自己設計的API介面, 歡迎各位朋友指教.

API設計理念

  1. 將涉及的實體抽象成資源, 即按id訪問資源, 在url上做文章, 以後再也不用為url起名字而苦惱了.
  2. 使用HTTP動詞對資源進行CRUD(增刪改查); get->查, post->增, put->改, delete->刪.
  3. URL命名規則, 對於資源無法使用一個單數名詞表示的情況, 我使用中橫線(-)連線.
    • 資源採用名詞命名, e.g: 產品 -> product
    • 新增資源, e.g: 新增產品, url -> /product , verb -> POST
    • 修改資源, e.g: 修改產品, url -> /products/{id} , verb -> PUT
    • 資源詳情, e.g: 指定產品詳情, url -> /products/{id} , verb -> GET
    • 刪除資源, e.g: 刪除產品, url -> /products/{id} , verb -> DELETE
    • 資源列表, e.g: 產品列表, url -> /products , verb -> GET
    • 資源關聯關係, e.g: 收藏產品, url -> /products/{id}/star , verb -> PUT
    • 資源關聯關係, e.g: 刪除收藏產品, url -> /products/{id}/star , verb -> DELETE

目前我API的設計只涉及這兩點, 至於第三點HATEOAS(Hypermedia As The Engine Of Application State)那就由讀者自己去選擇了.

專案地址

本文中只涉及了設計的理念, 具體的實現請下載原始碼rest-api, 專案內寫了比較詳細的註釋.

專案實戰

實戰將從業務場景出發, 詳細介紹如何使用HTTP verb對資源進行操作(狀態轉移), 使用JSON返回結果(資源表述), 並定義JSON的基礎結構.

JSON結構

requestParams:

{ }

responseBody:

{ "meta": { }, "data": { } }

meta中封裝操作成功或失敗的訊息, data中封裝返回的具體資料.

當新建商品或更新產品時, 相關屬性封裝在JSON中, 通過POST或PUT傳送,

{ "name": "Apple Watch SPORT", "description": "Sport 系列的錶殼材料為輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質為螢幕提供保護。搭配高效能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。" }

當使用者對商品進行操作後, 將得到響應結果,

GET, POST, PUT操作成功, 返回如下結果

{ "meta": { "code": 201, "message": "建立成功" }, "data": { "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "name": "Apple Watch SPORT", "description": "Sport 系列的錶殼材料為輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質為螢幕提供保護。搭配高效能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。" } }

DELETE操作成功, 返回如下結果

{ "meta": { "code": 204, "message": "刪除成功" } }

業務場景一

電商網站的管理員對商品進行新增,編輯,刪除,瀏覽的操作; 暫時不考慮認證授權, 只關注對商品的操作.

為了以後便於做分散式, 所有資源id(表主鍵)均採用uuid.

新增商品

1, url: /api/product

2, method: POST

3, requestParams:

{ "name": "Apple Watch SPORT", "description": "Sport 系列的錶殼材料為輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質為螢幕提供保護。搭配高效能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。" }

4, responseBody

{ "meta": { "code": 201, "message": "建立成功" }, "data": { "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "name": "Apple Watch SPORT", "description": "Sport 系列的錶殼材料為輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質為螢幕提供保護。搭配高效能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。" } }

編輯商品

1, url: /api/products/{id}

2, method: PUT

3, requestParams:

{ "name": "iPhone 6", "description": "此次蘋果釋出會釋出了iPhone 6與iPhone 6 Plus,搭載iOS 8,尺寸分別是4.7和5.5英寸。外觀設計不再稜角分明,表層玻璃邊有一個弧度向下延伸,與陽極氧化鋁金屬機身邊框銜接。機身背部採用三段式設計。機身更薄,續航能力更強。" }

4, responseBody

{ "meta": { "code": 200, "message": "修改成功" }, "data": { "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "name": "iPhone 6", "description": "此次蘋果釋出會釋出了iPhone 6與iPhone 6 Plus,搭載iOS 8,尺寸分別是4.7和5.5英寸。外觀設計不再稜角分明,表層玻璃邊有一個弧度向下延伸,與陽極氧化鋁金屬機身邊框銜接。機身背部採用三段式設計。機身更薄,續航能力更強。" } }

刪除商品

1, url: /api/products/{id}

2, method: DELETE

3, responseBody

{ "meta": { "code": 204, "message": "刪除成功" }, "data": {} }

獲取商品詳情

1, url: /api/products/{id}

2, method: GET

3, responseBody

刪除前

{ "meta": { "code": 200, "message": "查詢成功" }, "data": { "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "name": "Apple Watch SPORT", "description": "Sport 系列的錶殼材料為輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質為螢幕提供保護。搭配高效能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。" } } 刪除後

{ "meta": { "code": 404, "message": "指定產品不存在" } }

獲取商品列表(未分頁)

1, url: /api/products

2, method: GET

3, responseBody

{ "meta": { "code": 200, "message": "獲取全部商品成功" }, "data": [ { "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "name": "Apple Watch SPORT", "description": "Sport 系列的錶殼材料為輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質為螢幕提供保護。搭配高效能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。" }, { "id": "9db1992a-c342-4ff0-a2a4-aeb3dbfd93f6", "name": "Apple Watch SPORT", "description": "Sport 系列的錶殼材料為輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質為螢幕提供保護。搭配高效能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。" }, { "id": "4481619b-45c5-4729-9539-f93bb01f10d8", "name": "Apple Watch SPORT", "description": "Sport 系列的錶殼材料為輕巧的銀色及深空灰色陽極氧化鋁金屬,強化 Ion-X 玻璃材質為螢幕提供保護。搭配高效能 Fluoroelastomer 錶帶,共有 5 款繽紛色彩。" } ] }

業務場景二

業務場景一中只涉及了單個資源的操作, 但實際場景中還有些關聯操作; 如使用者去電商網站瀏覽商品, 並收藏了一些商品, 之後又取消收藏了部分商品.

暫時不考慮使用者認證授權, 以後加了token後, 使用者資訊可以從中獲取.

收藏商品

1, url: /api/products/{id}/star

2, method: PUT

3, responseBody

{ "meta": { "code": 200, "message": "收藏商品[5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9]成功" }, "data": [ { "id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "name": "iPhone 6", "description": "此次蘋果釋出會釋出了iPhone 6與iPhone 6 Plus,搭載iOS 8,尺寸分別是4.7和5.5英寸。外觀設計不再稜角分明,表層玻璃邊有一個弧度向下延伸,與陽極氧化鋁金屬機身邊框銜接。機身背部採用三段式設計。機身更薄,續航能力更強。" } ] }

取消收藏商品

1, url: /api/products/{id}/star

2, method: DELETE

3, responseBody

{ "meta": { "code": 200, "message": "刪除收藏商品[5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9]成功" }, "data": [] }

自定義異常和異常處理

所有自定義異常繼承RuntimeException, 在業務層丟擲, 統一在Controller層進行處理.

異常分為全域性異常和區域性異常, 例如http method unsupported(405), unauthorized(401), accessDenied(403), not found(404)等屬於全域性異常; 針對對獨立業務的一些異常屬於區域性異常, 例如產品編輯出錯;

異常在Controller中進行處理, 並封裝成json返回給前端, 封裝後的資料如下, 相關實現見原始碼;

{ "meta": { "code": 404, "message": "指定產品不存在" } } { "meta": { "code": 405, "message": "Request method 'POST' not supported" } }

專案執行截圖部分

本系列文章

  • 前後端完全分離初探
  • 前後端完全分離之API設計
  • 前後端完全分離之安全認證與授權-上
  • 前後端完全分離之安全認證與授權-下
  • 前後端完全分離之前端模組化開發
  • 前後端完全分離之前端路由系統
  • 前後端完全分離之後端面向服務的模組化開發

原文出自 前後端完全分離之API設計, 歡迎轉載, 轉載請註明出處.

相關文章