Alan Tsai 的學習筆記


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

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

2019-04-02 星期二
[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
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
2019-04-02 星期二
comments powered by Disqus