昨天我們用有限狀態機把代購 App 的訂單生命週期定義清楚——待採購、採購中、已購入、運送中、已送達、已取消,每個狀態能往哪裡轉、不能往哪裡轉,都畫成了圖。但那張圖畫在白板上不會自己動起來,前端要怎麼告訴後端「把這筆訂單從採購中轉成已取消」?後端又該怎麼拒絕一個不合法的轉換?這就是今天要談的:把昨天的狀態圖,變成一份前後端都遵守的合約——API。
RESTful(Representational State Transfer)是 Roy Fielding 在 2000 年的博士論文裡提出的架構風格,目的是讓分散式系統之間的溝通有一致的規則可循。對這系列最實用的幾個原則是:
RESTful 的核心習慣是:網址(URI)只用來說「這是什麼資源」,不描述「要做什麼」,動作交給 HTTP 方法決定。例如同樣是 /orders/123 這個網址:
GET /orders/123:查詢這筆訂單目前的狀態。PATCH /orders/123:修改這筆訂單的部分欄位,例如狀態。DELETE /orders/123:刪除這筆訂單。不會寫成 /getOrder123 或 /deleteOrder123 這種把動作寫進網址裡的設計。
**安全(Safe)**指的是這個方法不會改變伺服器上的資料,**冪等(Idempotent)**指的是同一個請求打一次跟打十次,結果都一樣。這兩個性質決定了重試一個請求安不安全:
HTTP 狀態碼分成幾個區間,光看第一碼就知道大方向:
前後端交換資料,現在幾乎都用 JSON——一種用文字表示資料結構的格式,可讀性好,幾乎每種語言都有現成的工具解析它。但光有 JSON 還不夠,兩邊還需要約定「這個資料長什麼樣子」,這時候需要兩層工具:
把昨天的訂單狀態機,接上今天的 API 設計:
買家要把訂單改成「已取消」,前端呼叫 PATCH /orders/123,帶上 { "status": "已取消" }。
後端收到請求後,第一件事不是直接改資料,而是先檢查:這筆訂單目前的狀態,允不允許轉換成「已取消」?
昨天畫在狀態機圖上的那條「限制線」——只有待採購、採購中能轉去已取消——到了 API 這一層,就是後端收到請求時實際要執行的那段檢查邏輯,而 409 這個狀態碼,就是後端用來告訴前端「你的請求邏輯上沒錯,但現在的狀態不允許」的正式語言。
這篇讓我理解狀態機圖跟 API 規格其實是同一件事的兩種畫法:狀態機圖是給人看的設計藍圖,API 規格是給機器執行的合約。昨天定義了「合法的路徑有哪些」,今天定義了「前端怎麼走這些路徑、後端怎麼守住不合法的路徑」。少了任何一邊,另一邊都只是紙上談兵——沒有 API,狀態機圖再嚴謹也不會真的擋下一次不合法的取消請求;沒有狀態機圖,API 的 409 判斷邏輯就會變成寫死在程式碼裡、沒人說得清楚規則的黑盒子。
我卡在哪裡:這篇沒有卡住。真正幫助我讀懂的是一個比喻——把 API 想成一把鑰匙:資源是門後面那個東西,不同的 HTTP 方法就像不同用途的鑰匙,有的只能開門看一眼(GET),有的可以把裡面的東西整個換掉或部分調整(PUT、PATCH),有的直接清空(DELETE)。有了這個畫面,前後端之間原本很抽象的溝通方式,就變成一種可以想像的制式語言,不再只是一堆要背的名詞。