Alan Tsai 的學習筆記


學而不思則罔,思而不學則殆,不思不學則“網貸” 記錄軟體開發的點點滴滴 著重於微軟技術、網頁開發、DevOps、C#, Asp .net Mvc、Azure、AI、Chatbot、Docker、Data Science

[apiary][04]設計API時好用的工具 - 讓前後端溝通格式不再卡卡 - API Blueprint Actions格式篇

2019-04-02 Tuesday
[apiary][04]設計API時好用的工具 - 讓前後端溝通格式不再卡卡 - API Blueprint Actions格式篇.jpg
圖片來源:https://pixabay.com/en/books-spine-colors-pastel-1099067/,logl來源:https://apiary.io/

在上一篇 ([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的部分有兩個:

  1. 定義URI Template的Parameters - 換句話説定義網址上面參數的部分
  2. 定義Request Payload - 當發生Post的時候要傳入的格式

Parameters - 用來定義URI Template的部分

回到之前的TODO 功能API的範例。

假設,今天取得所有的ToDo的這一支API想要加上一次出現幾筆資料,那麽一般來説這個設定會屬於網址的一部分,可能是用query string呈現或者route的一部分。

這個時候就是要用URI Template來定義。

大概操作會是:

  1. 調整路由,包含幾筆資料這個參數
  2. 增加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) - <描述>

定義好了之後,看文件的時候這兩個參數就會出現了:

chrome_2019-04-02_20-32-30.png
定義好的參數呈現樣子

Request 定義傳入的内容

一個TODO的APP如果不能夠新增的話,那麽就沒什麽用,所以要建立一個用來新增資料的API。

一般新增會挑選使用POST這個http verb,因此如果今天要定義一個接受JSON,裡面有個欄位是title,代表要建立的内容,那麽撰寫起來會是:

### 新增一筆TODO [POST]

用來新增一筆TODO

+ Request (application/json)

        {
            "title": "記得要買牛奶"
        }

其實還滿直覺,使用 Request區塊定義允許接受傳進來的内容,然後定義一個返利格式出來。

這個時候會好奇,怎麽定義欄位的格式?在下一篇MSON會介紹到。

最後呈現結果

Actions裡面透過Parameters以及Request定義了進來(request)的部分,那麽出去(response)的部分呢?

定義Action的Response部分

Response這個區塊有兩個主要部分:

  1. Headers - 定義回傳的資料Headers要包含什麽
  2. Body - 回傳的實際内容是什麽。如果沒有Headers,那麽預設任何定義的東西都是屬於body

一個Action可以有多個Response,例如當資料驗證不通過的時候,可能要回傳400等。

這邊分三個情況來看:

  1. 單純回傳body内容
  2. 回傳包含header内容
  3. 定義多個不同的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": "記得要買牛奶"
            }
chrome_2019-04-02_20-57-49.png
文件呈現的範例
上面可以看到,雖然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是必填欄位"
            }
2019-04-02_21-04-15.png
文件呈現效果,可以看到兩個response

雖然説這邊定義了兩個response,但是到了mock那邊還是只會回傳201那種情況,因此mock階段無法測試。

但是個人還是認爲這個很好,因爲當前端在做的時候,就會記得要處理error情況,同理後端也會記得其實有些驗證要做。

結語

這篇介紹了如何定義Actions裡面的request以及response。

可是寫到現在應該會發現幾個問題:

  1. 定義request以及response的json沒辦法定義每一個欄位的形態以及一些説明 - 因此雖然有範例,但是溝通可能還是有落差
  2. 有些json無法重複使用 - 有一些格式其實都一樣,例如資料的validation如果不通過,可能有個固定格式,但是目前只能用copy和paste的方式來定義,未來如果要改不就改到死?
  3. 有些欄位其實很類似,可能差別就在有沒有id - 有沒有辦法用繼承的概念來定義物件?

因爲這兩個原因,其實有另外一個定義物件格式的方式,這個格式叫做MSON

下一篇([apiary][05]設計API時好用的工具 - 讓前後端溝通格式不再卡卡 - MSON格式篇)將會介紹MSON,並且看看如何讓我們定義變得更加簡單並且能夠reuse。


如果文章對您有幫助,就請我喝杯飲料吧
街口支付QR Code
街口支付QR Code
台灣 Pay QR Code
台灣 Pay QR Code
Line Pay 一卡通 QR Code
Line Pay 一卡通 QR Code
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
2019-04-02 Tuesday
comments powered by Disqus