在上一篇 ([apiary][03]設計API時好用的工具 - 讓前後端溝通格式不再卡卡 - API Blueprint基本結構介紹篇) 瞭解了整個API Blueprint的基本結構之後,對於整個文件的架構應該有個比較充分的瞭解了。
但是上一篇因爲篇幅的關係,跳過了Actions裡面定義的部分。
Actions是什麽呢?基本上Actions就在定義某一之API可以接受的Request和Response是什麽。
這篇來看看怎麽定義。
一個基本的Action有什麽東西?
任何一支API基本上都有兩個部分:
- 預期的Request是什麽
- 這邊又有分,屬於網址的一部分,例如說是不是接受某一個query string可以用來控制目前要顯示幾筆資料,或者是payload也就是post過來的body的部分。
- 預期回復的Response是什麽
- 例如成功找到資料會回傳什麽回來,如果不成功會回傳什麽等等。
首先從Request裡面的url的部分開始看起。
定義Action的Request
Request的部分有兩個:
- 定義URI Template的Parameters - 換句話説定義網址上面參數的部分
- 定義Request Payload - 當發生Post的時候要傳入的格式
Parameters - 用來定義URI Template的部分
回到之前的TODO 功能API的範例。
假設,今天取得所有的ToDo
的這一支API想要加上一次出現幾筆資料,那麽一般來説這個設定會屬於網址的一部分,可能是用query string呈現或者route的一部分。
這個時候就是要用URI Template來定義。
大概操作會是:
- 調整路由,包含幾筆資料這個參數
- 增加
Parameters
,定義參數含義
- 調整路由,包含幾筆資料這個參數
以這邊的例子將會用
PageSize
作爲一次幾筆的參數,以及currentPage
代表目前是在第幾頁,那麽:### 取得所有的ToDo [GET /api/todo{?pageSize,currentPage}]
這邊用一個中括弧({})把所有的參數包起來,以問號(?)作爲開始表示屬於Query String,如果沒有問號則表示是URI的一部分。
- 增加 Parameters,定義參數含義
有了參數名稱之後,接下來就是要定義這些參數代表什麽意思。
首先會先增加一個
Parameters
的區塊,然後裡面列出每一個URI Template定義的參數説明。例如:
### 取得所有的ToDo [GET /api/todo{?pageSize,currentPage}] + Parameters + pageSize: 10 (number, optional) - 幾筆資料 + currentPage: 1 (number, optional) - 第幾頁
這邊要注意幾個地方
- 每一個開始都是用
+
做開頭 - 這個用來區分告知是某個區塊或者某一組 - 每一個大項目會投過空一行來作爲區隔
- 如果是在一起,但是是清單,那麽會寫在下一行,但是用tab或者4個空白表示下一層内容 - 例如
pageSize
就屬於Parameters
的一部分所以是用空一行然後tab
這邊定義欄位的格式是用一種叫做
MSON
的格式定義,詳細下一篇會介紹,但是基本格式為:<parameter 名稱>: `<範例值>` (<型別>, required | optional) - <描述>
- 每一個開始都是用
定義好了之後,看文件的時候這兩個參數就會出現了:
Request 定義傳入的内容
一個TODO的APP如果不能夠新增的話,那麽就沒什麽用,所以要建立一個用來新增資料的API。
一般新增會挑選使用POST
這個http verb,因此如果今天要定義一個接受JSON,裡面有個欄位是title
,代表要建立的内容,那麽撰寫起來會是:
### 新增一筆TODO [POST]
用來新增一筆TODO
+ Request (application/json)
{
"title": "記得要買牛奶"
}
其實還滿直覺,使用 Request
區塊定義允許接受傳進來的内容,然後定義一個返利格式出來。
Actions裡面透過Parameters以及Request定義了進來(request)的部分,那麽出去(response)的部分呢?
定義Action的Response部分
Response
這個區塊有兩個主要部分:
- Headers - 定義回傳的資料Headers要包含什麽
- Body - 回傳的實際内容是什麽。如果沒有Headers,那麽預設任何定義的東西都是屬於body
一個Action可以有多個Response,例如當資料驗證不通過的時候,可能要回傳400等。
這邊分三個情況來看:
- 單純回傳body内容
- 回傳包含header内容
- 定義多個不同的response
單純回傳body内容
首先以取得所有的ToDo
為例子,回傳的内容是一個array,裡面的物件就兩個欄位:id
以及title
:
### 取得所有的ToDo [GET /api/todo{?pageSize,currentPage}]
+ Parameters
+ pageSize: 10 (number, optional) - 幾筆資料
+ currentPage: 1 (number, optional) - 第幾頁
+ Response 200 (application/json)
[
{
"id": 1,
"title": "要買牛奶"
},
{
"id": 2,
"title": "要修好bug 123"
}
]
回傳包含header内容
如果説今天是呼叫了POST去建立一筆資料,如果今天走的是RESTFul的風格,那麽理論上header應該要回傳建立出來的資源的URI是什麽。
這個時候就可以用Headers
這個區塊,不過因爲有了Headers,那麽就需要明確定義那邊是Body
:
### 新增一筆TODO [POST]
用來新增一筆TODO
+ Request (application/json)
{
"title": "記得要買牛奶"
}
+ Response 201 (application/json)
+ Headers
Location: /api/todo/4
+ Body
{
"id": 4,
"title": "記得要買牛奶"
}
Headers
沒有定義Content-Type
,但是因爲明確指示回傳的是json,所以自動帶入
定義多個不同的response
有時候因爲傳入内容不同,response也會有所不同。
舉例來説,當呼叫POST的時候,但是title
是空的,那麽應該會回傳一個400帶訊息告訴說,title是必填欄位
這個時候就可以在加入一組Response
代表這個情況:
### 新增一筆TODO [POST]
用來新增一筆TODO
+ Request (application/json)
{
"title": "記得要買牛奶"
}
+ Response 201 (application/json)
+ Headers
Location: /api/todo/4
+ Body
{
"id": 4,
"title": "記得要買牛奶"
}
+ Response 400 (application/json)
驗證失敗
+ Body
{
"erroMessage": "title是必填欄位"
}
雖然説這邊定義了兩個response,但是到了mock那邊還是只會回傳201那種情況,因此mock階段無法測試。
但是個人還是認爲這個很好,因爲當前端在做的時候,就會記得要處理error情況,同理後端也會記得其實有些驗證要做。
結語
這篇介紹了如何定義Actions
裡面的request以及response。
可是寫到現在應該會發現幾個問題:
- 定義request以及response的json沒辦法定義每一個欄位的形態以及一些説明 - 因此雖然有範例,但是溝通可能還是有落差
- 有些json無法重複使用 - 有一些格式其實都一樣,例如資料的validation如果不通過,可能有個固定格式,但是目前只能用copy和paste的方式來定義,未來如果要改不就改到死?
- 有些欄位其實很類似,可能差別就在有沒有id - 有沒有辦法用繼承的概念來定義物件?
因爲這兩個原因,其實有另外一個定義物件格式的方式,這個格式叫做MSON。
下一篇([apiary][05]設計API時好用的工具 - 讓前後端溝通格式不再卡卡 - MSON格式篇)將會介紹MSON,並且看看如何讓我們定義變得更加簡單並且能夠reuse。