iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Software Development

文科生的軟體工程啟蒙:用一個代購 App,看懂 30 個系統設計觀念系列 第 5

Day 5:介面合約設計——RESTful 原則、API 規格定義與資料交換協議

  • 分享至 

  • xImage
  •  

昨天我們用有限狀態機把代購 App 的訂單生命週期定義清楚——待採購、採購中、已購入、運送中、已送達、已取消,每個狀態能往哪裡轉、不能往哪裡轉,都畫成了圖。但那張圖畫在白板上不會自己動起來,前端要怎麼告訴後端「把這筆訂單從採購中轉成已取消」?後端又該怎麼拒絕一個不合法的轉換?這就是今天要談的:把昨天的狀態圖,變成一份前後端都遵守的合約——API。

一、RESTful 原則

RESTful(Representational State Transfer)是 Roy Fielding 在 2000 年的博士論文裡提出的架構風格,目的是讓分散式系統之間的溝通有一致的規則可循。對這系列最實用的幾個原則是:

  • 用戶端與伺服端分離 Client-Server:前端只負責畫面,後端只負責資料與邏輯,兩邊透過 API 溝通,各自可以獨立開發、獨立部署。
  • 無狀態 Stateless:每一次請求都必須帶齊這次需要的所有資訊,伺服器不會記得你上一次的請求是什麼。買家每次呼叫 API,都要附上自己的登入憑證,而不是指望伺服器「記得」他剛剛登入過。
  • 統一介面 Uniform Interface:資源用網址識別(例如一筆訂單就是一個網址),操作資源用標準化的方法(GET、POST 這些),伺服器回傳的東西要「自我解釋」,讓用不同語言、不同前端框架的團隊都看得懂同一份 API。
  • 可快取 Cacheable:伺服器的回應要註明能不能被暫存,讀取量大的資料(例如商品列表)快取起來,能大幅減少重複查詢的負擔。

二、API 規格定義

(一)用網址代表資源,用方法代表動作

RESTful 的核心習慣是:網址(URI)只用來說「這是什麼資源」,不描述「要做什麼」,動作交給 HTTP 方法決定。例如同樣是 /orders/123 這個網址:

  • GET /orders/123:查詢這筆訂單目前的狀態。
  • PATCH /orders/123:修改這筆訂單的部分欄位,例如狀態。
  • DELETE /orders/123:刪除這筆訂單。

不會寫成 /getOrder123/deleteOrder123 這種把動作寫進網址裡的設計。

(二)方法的安全與冪等

**安全(Safe)**指的是這個方法不會改變伺服器上的資料,**冪等(Idempotent)**指的是同一個請求打一次跟打十次,結果都一樣。這兩個性質決定了重試一個請求安不安全:

  • GET:安全,也冪等,可以放心重複呼叫。
  • PUT、DELETE:不安全(會改資料),但冪等——刪同一筆訂單刪十次,結果都是「這筆訂單不存在」,跟刪一次一樣。
  • POST、PATCH:不安全,也不保證冪等。連續送出兩次「新增訂單」的 POST,很可能會建立兩筆一模一樣的訂單,這也是為什麼「送出」按鈕常常要在送出後立刻 disable。

(三)用狀態碼溝通結果

HTTP 狀態碼分成幾個區間,光看第一碼就知道大方向:

  • 2xx 成功:200 表示請求成功且有內容回傳,201 表示成功建立了新資源(例如買家送出新訂單)。
  • 4xx 客戶端的問題:400 表示請求格式有誤,401 表示沒有登入或憑證失效,404 表示資源不存在,409 表示請求本身沒錯,但跟伺服器目前的狀態衝突——這正是我們今天要用到的狀態碼。
  • 5xx 伺服端的問題:500 表示伺服器發生未預期的錯誤,前端拿到 5xx 通常代表「不是你的問題,晚點再試」。

三、資料交換協議

前後端交換資料,現在幾乎都用 JSON——一種用文字表示資料結構的格式,可讀性好,幾乎每種語言都有現成的工具解析它。但光有 JSON 還不夠,兩邊還需要約定「這個資料長什麼樣子」,這時候需要兩層工具:

  • OpenAPI(前身是 Swagger):一份描述整支 API 的規格文件,寫清楚有哪些網址、支援哪些方法、需要帶什麼參數、會回傳什麼——前後端可以照著這份文件各自開發,不用互相口頭確認。
  • JSON Schema:專門用來描述「一筆 JSON 資料應該長什麼樣子」的規則,例如「status 欄位必須是字串,且只能是這五個值其中之一」。前端送出的資料、後端回傳的資料,都可以拿這份規則去驗證格式對不對。

四、代購 App 實例:用 API 觸發狀態轉換

把昨天的訂單狀態機,接上今天的 API 設計:

買家要把訂單改成「已取消」,前端呼叫 PATCH /orders/123,帶上 { "status": "已取消" }

後端收到請求後,第一件事不是直接改資料,而是先檢查:這筆訂單目前的狀態,允不允許轉換成「已取消」?

  • 如果目前狀態是「待採購」或「採購中」:轉換合法,更新資料庫,回傳 200,並附上更新後的訂單內容。
  • 如果目前狀態已經是「運送中」:轉換不合法,後端拒絕這次更新,回傳 409 Conflict,並在回應內容裡說明「訂單已進入運送流程,無法取消」。

昨天畫在狀態機圖上的那條「限制線」——只有待採購、採購中能轉去已取消——到了 API 這一層,就是後端收到請求時實際要執行的那段檢查邏輯,而 409 這個狀態碼,就是後端用來告訴前端「你的請求邏輯上沒錯,但現在的狀態不允許」的正式語言。

五、結論

這篇讓我理解狀態機圖跟 API 規格其實是同一件事的兩種畫法:狀態機圖是給人看的設計藍圖,API 規格是給機器執行的合約。昨天定義了「合法的路徑有哪些」,今天定義了「前端怎麼走這些路徑、後端怎麼守住不合法的路徑」。少了任何一邊,另一邊都只是紙上談兵——沒有 API,狀態機圖再嚴謹也不會真的擋下一次不合法的取消請求;沒有狀態機圖,API 的 409 判斷邏輯就會變成寫死在程式碼裡、沒人說得清楚規則的黑盒子。

我卡在哪裡:這篇沒有卡住。真正幫助我讀懂的是一個比喻——把 API 想成一把鑰匙:資源是門後面那個東西,不同的 HTTP 方法就像不同用途的鑰匙,有的只能開門看一眼(GET),有的可以把裡面的東西整個換掉或部分調整(PUT、PATCH),有的直接清空(DELETE)。有了這個畫面,前後端之間原本很抽象的溝通方式,就變成一種可以想像的制式語言,不再只是一堆要背的名詞。


上一篇
Day 4:資訊架構與狀態生命週期——UI 狀態遷移與有限狀態機(FSM)概念
下一篇
記憶體中的資料組織——Array vs. Object 在資料查詢與更新上的工程權衡
系列文
文科生的軟體工程啟蒙:用一個代購 App,看懂 30 個系統設計觀念6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言