RESTful API 設計流程,共四步驟:
- 設計資源的 URL 路徑
- 將 API 操作對應到 HTTP Method
- 設定 Status Code
- 展開 Request 與 Response
提供設計範例一步步完成。
▍第一步:設計資源的 URL 路徑
- 定義資源
- 遵循命名規則,設計URL
RESTful API Endpoint Naming Strategies: Best Practices- API 的 URI 請勿使用駝峰命名法 ,應始終為小寫。
- 使用連字符 " - " 而不是底線分隔多個單字。
- 不要縮寫,URI 中的單字要使用完整且有意義的形式。
- 如果API 接受變數,則應使用駝峰式命名法表示它,並括在一組大括號 { } 內。
e.g.,https://localhost:2024/api/co-agents?emailAdress={emailAdress}&firstName={firstName}
- 使用正斜線表示層次關係。
- 資源名稱使用名詞,而不是動詞。
- 應該使用複數名詞來表示集合。
下方以包含多種契約的線上簽名系統為例子。
資源名稱 | 資源路徑 |
---|---|
E-signing | /esigning |
E-signing's Appointment To Sell Letters | /esigning/appointment-to-sell-letters |
E-signing's Co-broke Letters | /esigning/co-broke-letters |
▍第二步:將 API 操作對應到 HTTP Method
主要的 HTTP Method:
HTTP Method | 說明 | 安全性 (註1) | 冪等性 (註2) | 說明 |
---|---|---|---|---|
GET | 回覆請求資料 Read | Safe | Idempotent | 具有冪等性,相同的查詢請求,不管查詢幾次都應該得到相同的結果。 |
POST | 創建資源或其他應用 Create | Unsafe | 不具冪等性,相同的建立請求,每次執行,都會建立一個新的資源。 | |
PUT | 取代現有資源 Update | Unsafe | Idempotent | 具冪等性,每次執行更新請求,皆使用同樣的資料覆蓋指定的資源,所以結果不變。 |
PATCH | 更新資源 Update | Unsafe | 不具冪等性,但可以以冪等的方式發出請求。 | |
DELETE | 刪除資源 Delete | Unsafe | Idempotent | 具冪等性,刪除資源後,無論重複多少次刪除,也不會改變結果。 |
註1:
關於安全性,RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1) 中關於Safe Methods的說明:
Request methods are considered "safe" if their defined semantics are essentially read-only; i.e., the client does not request, and does not expect, any state change on the origin server as a result of applying a safe method to a target resource. Likewise, reasonable use of a safe method is not expected to cause any harm, loss of property, or unusual burden on the origin server.
簡單的說,Safe method 不應該造成資料的改變。
也就是不應該用 Safe method 去改資料。
而這也代表著 Safe method 只提供讀取資料或讀取狀態行為(不改資料,換句話說就是只能讀取)。
( 參考 HTTP 的 Safe method 還有 Idempotent method )
註2:
Idempotent 冪等性:是HTTP方法的屬性,表示不管執行多少次操作請求,都將產生相同的結果。
( 參考 Idempotency Key:原理與實測 )
下方以同業合作契約 Co-broke Letters舉例。
用 HTTP Method 做同業合作契約的 CRUD:
Create → 用 POST
Read → 用 GET
Update → 用 PATCH or PUT
Delete → 用 DELETE
資源路徑 URL | 操作名稱 Action Name | HTTP Method | 說明 | 請求參數 Request | 回應 Response |
---|---|---|---|---|---|
/esigning/co-broke-letters | CreateCobrokeLetter | POST | 建立同業合作線上簽名契約 | createRequest | 找到這筆資料的URL, cobrokeLetterId, response 201 Created 已建立 400 Bad Request 錯誤的要求 |
/esigning/co-broke-letters/ {cobrokeLetterId} | UpdateCobrokeLetter | PATCH | 更新同業合作契約 | cobrokeLetterId、updateRequest | 204 NoContent 無內容 (成功不回傳內容) 400 Bad Request 錯誤的要求 404 Not Found 找不到 |
/esigning/co-broke-letters/ {cobrokeLetterId} | GetCobrokeLetter | GET | 取得一份同業合作契約 | cobrokeLetterId | cobrokeLetter 200 OK 成功 (回傳內容) 404 Not Found 找不到 |
/esigning/co-broke-letters/ conditions?keyWord={keyWord}& signStatus={signStatus} | SearchCobrokeLetters | GET | 依請求參數搜尋 e.g.,關鍵字、簽名狀態… | Query String: keyWord、signStatus | cobrokeLetter[] 200 OK 成功 (回傳內容) |
/esigning/co-broke-letters/ {cobrokeLetterId} | DeleteCobrokeLetter | DELETE | 刪除同業合作契約 | cobrokeLetterId | 204 NoContent 無內容 (成功不回傳內容) 404 Not Found 找不到 |
▍第三步:設定 Status Code
上方同業合作契約表格範例已經放入 Status Code。
常見的 Status Code:
- 2XX(成功類)OK:請求被成功接收並處理完成。
- 200:OK。請求成功並回應。
- 201:Created。請求建立新增資源成功。
- 204:NoContent。請求成功,沒有回覆任何內容,通常用於刪除的內容。
- 3XX(重新定向/轉址)Redirection:需要進一步行動才能完成請求。
- 301:成功轉址
- 4 XX(客戶端錯誤)Client Error:該請求包含錯誤語法或無法滿足。
- 400:Bad Request。錯誤的要求。
- 403:Forbidden。伺服器拒絕請求,權限不夠、授權不夠。
- 404:Not Found。請求的URL或URI不存在,打錯網址,或資源不存在。
- 415:Unsupported Media Type。不支援的媒體類型,用了不符合的content-type。
e.g.,只收Json格式,不收html。所以收到415。
1. 可以先懷疑:Header 裡面的 content-type 帶入錯了
2. 或是自己寫的 Header和 Payload 的 content-type 不吻合
- 5XX(伺服器錯誤)Server Error:伺服器因為發生錯誤或例外狀況(Exception) 而無法完成請求 (Request)。
- 500:Internal Sever Error。內部伺服器錯誤,無法處理請求。
▍第四步:展開 Request 與 Response
完成 API 規格總表後,接著將每一列的操作,展開細節。
首先,將總表的第一列操作 (如下表) 的細節寫在下方。
資源路徑 URL | 操作名稱 Action Name | HTTP Method | 說明 | 請求參數 Request | 回應 Response |
---|---|---|---|---|---|
/esigning/co-broke-letters | CreateCobrokeLetter | POST | 建立同業合作線上簽名契約 | createRequest | 找到這筆資料的URL, cobrokeLetterId, response 201 Created 已建立 400 Bad Request 錯誤的要求 |
重點是讓看文件的人好懂,能準確寫出需要的 API 功能。
下方示範的是我目前的寫法與習慣,給大家一個參考。
再找出自己能有效率製作、並與團隊能有效率溝通的文件格式。
POST ~/esigning/co-broke-letters
功能:建立同業合作契約資料
Action Name:CreateCobrokeLetter
Request 請求參數:createRequest
Body 參數名稱 | 是否必填 | 資料類型 | 說明 |
---|---|---|---|
CreateDate | V | DateTime | 建立契據日期 |
CreateUserId | V | string | 建立契據人編號 |
CommunityName | string | 社區名字 | |
CoAgentDataId | V | int | 同業資料Id |
請求範例:格式 json
POST https://localhost:40088/api/esign/cobroke-letters
Content-Type: application/json
{
"CreateDate": "2023-10-17",
"CreateUserId": "39513",
"CommunityName": "Tiffany Kiara",
"CoAgentDataId": "5"
}
Response 回傳參數:
參數名稱 | 資料類型 | 說明 |
---|---|---|
Id | int | 同業合作契約Id |
回傳情境:
- 成功:
- 201 Created
回傳可以得到此筆資料的URL(往下讀會找到GET的URL⭐)、此筆記錄建立後得到的同業合作契約Id
- 201 Created
{
"Url":".../esigning/co-broke-letters/{cobrokeLetterId}",
"Id":"1"
}
- 失敗:
- 500 Internal Sever Error
API本人掛了 > 回傳錯誤訊息
- 400 Bad Request
errorMessage:格式不符合
- 500 Internal Sever Error
{
"CreateUserId": "CreateUserId must Has 6 characters.",
"Detail": "CreateUserId must Has 6 characters.",
"Instance": "api/esign/cobroke-letters"
}
完成一個了!接下來以此類推。
讓我繼續推下去~
PATCH ~/esigning/co-broke-letters/{id}
功能:更新同業合作契約資料
Action Name:UpdateCobrokeLetter
Request 請求參數:id
、updateRequest
Body 參數名稱 | 是否必填 | 資料類型 | 說明 |
---|---|---|---|
Id | V | int | 同業合作契約Id |
CreateDate | V | DateTime | 建立契據日期 |
CreateUserId | V | string | 建立契據人編號 |
CommunityName | string | 社區名字 | |
CoAgentDataId | V | int | 同業資料Id |
請求範例:格式 json
PATCH https://localhost:40088/api/esign/cobroke-letters/1
Content-Type: application/json
{
"CreateDate": "2023-10-17",
"CreateUserId": "395135",
"CommunityName": "Mont Kiara",
"CoAgentDataId": ""
}
Response 回傳參數:NoContent
回傳情境:
- 成功:
- 204 NoContent
成功,不回傳內容。
- 204 NoContent
- 失敗:
- 500 Internal Sever Error
API本人掛了 > 回傳錯誤訊息
- 400 Bad Request
errorMessage:格式不符合
- 500 Internal Sever Error
{
"CreateUserId": "CoAgentDataId is required.",
"Detail": "CoAgentDataId is required.",
"Instance": "api/esign/cobroke-letters"
}
GET ~/esigning/co-broke-letters/{id}
⭐這個URL就是前面POST建立契約時,201建立成功要回傳的URL。
功能:取得一份同業合作契約
Action Name:GetCobrokeLetter
Request 請求參數:id
Body 參數名稱 | 是否必填 | 資料類型 | 說明 |
---|---|---|---|
Id | V | int | 同業合作契約Id |
請求範例:格式 json
GET https://localhost:40088/api/esign/cobroke-letters/1
Response 回傳參數:cobrokeLetter
回傳情境:
- 成功:
- 200 OK 成功
回傳Id為1的cobrokeLetter資料內容。
- 200 OK 成功
{
"Id":"1",
"CreateDate": "2023-10-17",
"CreateUserId": "395135",
"CommunityName": "Tiffany Kiara",
"CoAgentDataId": "5"
}
- 失敗:
- 404 Not Found 找不到
GET ~/esigning/co-broke-letters/conditions?createUserId={createUserId}&
communityName={communityName}
功能:依請求參數搜尋
Action Name:SearchCobrokeLetters
Request 請求參數:Query String
Body 參數名稱 | 是否必填 | 資料類型 | 說明 |
---|---|---|---|
CreateUserId | string | 建立契據人編號 | |
CommunityName | string | 社區名字 |
請求範例:格式 json
GET https://localhost:40088/api/esign/cobroke-letters/conditions?createUserId={395135}&communityName={Kiara}
- 如果 Query String 都沒放內容,我會讓系統篩選出全部的同業合作契約。
- 名稱類的參數 e.g.,
communityName
,我會讓系統模糊搜尋。
Response 回傳參數:cobrokeLetter[]
回傳情境:
- 成功:
- 200 OK
回傳cobrokeLetter[] 同業合作契約的資料集合。
- 200 OK
DELETE~/esigning/co-broke-letters/{id}
功能:刪除同業合作契約
Action Name:DeleteCobrokeLetter
Request 請求參數:id
Body 參數名稱 | 是否必填 | 資料類型 | 說明 |
---|---|---|---|
Id | V | int | 同業合作契約Id |
請求範例:格式 json
DELETE https://localhost:40088/api/esign/cobroke-letters/1
Response 回傳參數:NoContent
回傳情境:
- 成功:
- 204 NoContent
成功,不回傳內容。
- 204 NoContent
- 失敗:
- 404 Not Found 找不到
將 Request 和 Response 展開細節就完成了API設計了!
之後會有一篇說明如何驗證請求 Validate Request,當 Request不符合規則時就會顯示錯誤訊息提醒使用者。
以上步驟就完成設計 Web API 規格文件了😊
再看一個網路上買書的例子,使用購物車 Cart 與書 Book。
參考《Web API設計原則: API與微服務傳遞價值之道》。
資源路徑 URL | 操作名稱 Action Name | HTTP Method | 說明 | 請求參數 Request | 回應 Response |
---|---|---|---|---|---|
/books/conditions? categoryId={categoryId}& releaseDate={releaseDate} | searchBooks | Get | 依請求參數搜尋 e.g.,分類、出版日期… | Query StringcategoryId 、releaseDate | Book[] 200 |
/books/{bookId} | viewBook | Get | 檢視一本書的詳情 | bookId | Book 200, 404 |
/carts/{cartId}/items | addBookToCart | Post | 將書籍加入用戶購物車 | cartId | Cart 201, 400 |
/carts/{cartId}/items/{cartItemId} | removeBookFromCart | Delete | 將書籍自用戶的購物車移除 | cartItemId | Cart 204, 404 |
/carts/{cartId} | clearCart | Delete | 將用戶購物車的全部品項移除 | cartId | Cart 204, 404 |
/carts/{cartId} | viewCart | Get | 檢視當前購物車的品項 | cartId | Cart 200, 404 |
參考資料
James Higginbotham ─《Web API設計原則: API與微服務傳遞價值之道》一書
RESTful API Endpoint Naming Strategies: Best Practices
謝謝觀看,此為新手的學習筆記整理,若有錯誤,煩請指正🙏