首先請熟悉以下的兩個(gè)文檔:
API 設(shè)計(jì)上有無法抉擇的地方,應(yīng)該參考 GitHub 的 API 文檔:
GitHub 的 RESTful API 設(shè)計(jì)是業(yè)內(nèi)比較知名的。
所有的 API,早期設(shè)計(jì)時(shí)都 必須 考慮版本控制。
隨著業(yè)務(wù)的發(fā)展,需求的不斷變化,API 的迭代是必然的,很可能當(dāng)前版本正在使用,而我們就得開發(fā)甚至上線一個(gè)不兼容的新版本,為了讓舊用戶可以正常使用,為了保證開發(fā)的順利進(jìn)行,我們需要控制好 API 的版本。
將版本號直接加入 URL 中:
https://api.example.com/v1
https://api.example.com/v2
https://api.example.com/v3
開發(fā) API 時(shí),必須使用 RESTful 規(guī)范來架構(gòu) API。
具體規(guī)則下面羅列出來。
必須使用 URL 定位資源的規(guī)則。
在 RESTful 的架構(gòu)中,所有的一切都表示資源,每一個(gè) URL 都代表著一種資源,資源應(yīng)當(dāng)是一個(gè)名詞,而且大部分情況下是名詞的復(fù)數(shù),盡量不要在 URL 中出現(xiàn)動詞。
先來看看 GitHub 的 例子:
GET /issues 列出所有的 issue
GET /orgs/:org/issues 列出某個(gè)項(xiàng)目的 issue
GET /repos/:owner/:repo/issues/:number 獲取某個(gè)項(xiàng)目的某個(gè) issue
POST /repos/:owner/:repo/issues 為某個(gè)項(xiàng)目創(chuàng)建 issue
PATCH /repos/:owner/:repo/issues/:number 修改某個(gè) issue
PUT /repos/:owner/:repo/issues/:number/lock 鎖住某個(gè) issue
DELETE /repos/:owner/:repo/issues/:number/lock 解鎖某個(gè) issue
例子中冒號開始的代表變量,例如 /repos/summerblue/larabbs/issues
在 GitHub 的實(shí)現(xiàn)中,我們可以總結(jié)出:
資源的設(shè)計(jì)可以嵌套,表明資源與資源之間的關(guān)系。
大部分情況下我們訪問的是某個(gè)資源集合
,想得到單個(gè)資源
可以通過資源的 id 或 number 等唯一標(biāo)識獲取。
某些情況下,資源會是單數(shù)形式,例如某個(gè)項(xiàng)目某個(gè) issue 的鎖
,每個(gè) issue 只會有一把鎖,所以它是單數(shù)。
? 錯(cuò)誤的例子:
POST https://api.example.com/createTopic
GET https://api.example.com/topic/show/1
POST https://api.example.com/topics/1/comments/create
POST https://api.example.com/topics/1/comments/100/delete
? 正確的例子:
POST https://api.example.com/topics
GET https://api.example.com/topics/1
POST https://api.example.com/topics/1/comments
DELETE https://api.example.com/topics/1/comments/100
Laravel 應(yīng)該使用以下來定義資源路由:
Route::apiResource('users', UserController::class);
以上等同于:
Verb Path Action Route Name
GET /users index users.index
POST /users store users.store
GET /users/{user} show users.show
PUT|PATCH /users/{user} update users.update
DELETE /users/{user} destroy users.destroy
如果你不使用 apiResource()
方法,控制器方法 必須 按照以上的指紋來定義路由。
apiResource()
還可以使用以下方法來定制具體使用的路由:
Route::apiResource('photos', PhotoController::class)->only([
'index', 'show'
]);
Route:: apiResource('photos', PhotoController::class)->except([
'create', 'store', 'destroy'
]);
必須使用 HTTP 動詞來描述操作,絕不單一的使用 POST 來處理所有邏輯。
HTTP 設(shè)計(jì)了很多動詞,來表示不同的操作,RESTful 很好的利用的這一點(diǎn),我們需要正確的使用 HTTP 動詞,來表明我們要如何操作資源。
先來解釋一個(gè)概念,冪等性
,指一次和多次請求某一個(gè)資源應(yīng)該具有同樣的副作用,也就是一次訪問與多次訪問,對這個(gè)資源帶來的變化是相同的。
常用的動詞及冪等性
動詞 | 描述 | 是否冪等 |
---|---|---|
GET | 獲取資源,單個(gè)或多個(gè) | 是 |
POST | 創(chuàng)建資源 | 否 |
PUT | 更新資源,客戶端提供完整的資源數(shù)據(jù) | 是 |
PATCH | 更新資源,客戶端提供部分的資源數(shù)據(jù) | 否 |
DELETE | 刪除資源 | 是 |
為什么 PUT 是冪等的而 PATCH 是非冪等的,因?yàn)?nbsp;PUT 是根據(jù)客戶端提供了完整的資源數(shù)據(jù),客戶端提交什么就替換什么,而 PATCH 有可能是根據(jù)客戶端提供的參數(shù),動態(tài)的計(jì)算出某個(gè)值,例如每次請求后資源的某個(gè)參數(shù)減 1,所以多次調(diào)用,資源會有不同的變化。
另外需要注意的是,GET 請求對于資源來說是不安全的,絕不 通過 GET 請求改變(更新或創(chuàng)建)資源。
真實(shí)使用中,為了方便統(tǒng)計(jì)類的數(shù)據(jù),會有一些例外情況,例如帖子詳情,記錄訪問次數(shù),每調(diào)用一次,訪問次數(shù) +1。這種情況下可以考慮頁面展示成功后,再次調(diào)用一個(gè) POST 請求去更新閱讀數(shù)。
必須利用 HTTP 狀態(tài)碼和客戶端進(jìn)行通訊。
有一些 API 的設(shè)計(jì),不論接口的狀態(tài)成功與否,都會返回 200 ,然后使用自定的狀態(tài)碼,例如說 :
{
// 數(shù)據(jù)不存在
error_code: 30404
}
這種方法是不可取的。
HTTP 狀態(tài)碼是行業(yè)標(biāo)準(zhǔn),意味著成千上萬開發(fā)者都在認(rèn)同和使用這套規(guī)則,意味著他們寫出來的 HTTP 通訊程序(類庫)也在使用這套規(guī)則。所以沒有必要,也不該重新發(fā)明自己的一套規(guī)則。
HTTP 提供了豐富的狀態(tài)碼供我們使用,正確的使用狀態(tài)碼可以讓響應(yīng)數(shù)據(jù)更具可讀性。、
強(qiáng)制客戶端在請求時(shí),必須發(fā)送 User-Agent 信息。
User-Agent 信息包含兩部分,客戶端信息 + 版本,使用斜桿分隔:
User-Agent: Mixin Bot iOS/2.1.37
User-Agent: Mixin Bot Android/2.1.22
User-Agent: MixPay PHP SDK/2.1.22
User-Agent: MixPay GO SDK/2.1.22
API 后端接收到 User-Agent 數(shù)據(jù)后可以暫時(shí)不做處理,但是后續(xù)有特殊的業(yè)務(wù)需求時(shí),可以針對某個(gè)客戶端具體到版本,進(jìn)行特殊的數(shù)據(jù)處理。
常見的使用場景,是廢棄客戶端:例如一個(gè)銀行 APP,升級了交易時(shí)的加密算法,低于 5.0 版本的客戶端因?yàn)榘踩?,必須廢棄。針對此情況,可通過后端 API 判斷 User-Agent 標(biāo)頭,對低于 5.0 的版本的客戶端請求,返回專屬的數(shù)據(jù),如 APP 首頁的第一個(gè) Banner 顯示請升級客戶端,安全升級無法使用的提示。
現(xiàn)實(shí)生產(chǎn)中,有些客戶端用戶會關(guān)閉系統(tǒng)的應(yīng)用自動更新功能,多版本客戶端是無法避免的問題。有了 User-Agent ,我們可以更加靈活的做針對性處理。
資源路由路由 URI 必須 使用復(fù)數(shù)形式,如:
/photos/create
/photos/{photo}
錯(cuò)誤的例子如:
/photo/create
/photo/{photo}
更多建議: