在上一篇([apiary][04]設計API時好用的工具 - 讓前後端溝通格式不再卡卡 - API Blueprint Actions格式篇)介紹了如何定義Actions,換句話説,以目前的知識要定義出一個API已經沒有什麽問題了。
但是在上一篇還有遇到一個問題,那就是不管是request或者response的JSON物件沒有定義出來裡面的欄位以及説明。換句話説,目前的方式只有範例,但是每一個欄位的形態,描述沒有辦法定義。
Apiary團隊當初考慮到了這一個問題,因此建立出一個格式稱之爲Markdown Syntax for Object Notation (MSON),專門用來描述JSON以及JSON Schema。
這邊來看看MSON怎麽使用。
MSON是什麽
MSON的全稱是:Markdown Syntax for Object Notation ,白話來説,就是可以用類似markdown的語法定義出JSON以及JSON Schema,因此可以透過這個語法定義好request以及response的物件訊息。
MSON雖然主要是用在API Blueprint裡面定義格式,不過MSON本身也是一個open standard的格式(RFC 2119),換句話説API Blueprint和MSON可以分開兩塊來看。
接下來,先看MSON的格式如何定義JSON,然後在看看怎麽在API Blueprint裡面透過Attributes
來使用。
MSON的基本格式
這邊一樣沿用之前的例子,如果說今天要定義一筆ToDo的格式看看會怎麽用MSON來定義。
這邊拆幾個情景來看:
- 基本物件定義方式
- 欄位是另外一個複雜物件
- 内建特殊形態:如何定義array
- 内建特殊形態:如何定義enum
基本物件定義方式
假設今天最後的JSON結果是:
{
"id": 1,
"title": "要買牛奶"
}
那麽在MSON裡面就會是:
+ id: 1 (number, required) - 資料的Id
+ title: `要買牛奶` (string, required) - todo 的描述
從這個範例可以看出,一個欄位的結構大概是:+ {欄位名稱}: {範例值} ({形態}, {required | optional}) - {欄位描述}
Parameters
的寫法結構一樣。
欄位是另外一個複雜物件
基本的物件定義的出來了,如果說今天要複雜一點呢?
舉例來説,假設今天todo要多分類的概念,可以讓使用者自訂分類,這個時候就要多欄位出來。
假設最後的json物件是:
{
"id": 1,
"title": "要買牛奶",
"category": {
"id": 1,
"name": "要買"
}
}
那麽MSON就會是:
+ id: 1 (number, required) - 資料的Id
+ title: `要買牛奶` (string, required) - todo 的描述
+ category
+ id: 1 (number, required) - 分類的Id
+ name: `要買` (string, required) - 分類名稱
從上面的範例可以看出,如果一個type是另外一個物件(以範例來説是category
),那麽只需要把裡面的property前面先加一個tab,其他同一般欄位定義方式一樣即可。
内建特殊形態:如何定義array
能夠定義欄位,以及欄位是另外一個物件的方法了之後,接下來在介紹兩個比較特別的形態:enum
以及array
。
首先來看array,假設今天分類可以有多筆,這個時候就要變成array了。假設最後的json是:
{
"id": 1,
"title": "要買牛奶",
"categories": [
{
"id": 1,
"name": "要買"
}
]
}
那麽對應的MSON就會變成:
+ id: 1 (number, required) - 資料的Id
+ title: `要買牛奶` (string, required) - todo 的描述
+ categories (array)
+ (object)
+ id: 1 (number, required) - 分類的Id
+ name: `要買` (string, required) - 分類名稱
這次的修改有:
- 把
category
改成了categories
表示是複數 - 由於變成了array,因此
categories
的形態特別定義爲array
- 由於array裡面的物件不需要欄位名稱,因此array下面的第一個property只有定義為
object
,但是沒有property名稱 - 在
(object)
下面定義的就是物件的欄位
内建特殊形態:如何定義enum
接下來看看另外一個特殊形態,enum
。
有時候有些欄位只有特定幾個值,這個時候會用enum避免值有錯。
以目前的例子,假設需要一個欄位代表目前這個todo的狀態,那麽json的範例會是:
{
"id": 1,
"title": "要買牛奶",
"state": "0"
}
MSON定義起來會是:
+ id: 1 (number, required) - 資料的Id
+ title: `要買牛奶` (string, required) - todo 的描述
+ state: 0 (enum)
+ 0 - 表示這個task已經完成
+ 1 - 表示這個task已經過期
+ 2 - 表示這個task尚未開始
MSON:客制形態,讓形態可以被重複使用
上面的部分已經把怎麽用MSON定義物件的方式介紹完了,不過就算改成了MSON讓定義變得容易並且簡單,但是不好重複使用。
舉例來説,今天取得1筆ToDo得到的物件,和取多筆得到的物件可能從欄位來説是一樣的,那要重複寫兩次不是很傻?更別説如果需要調整,到時候修改很容易改到了一個但是漏掉了另外一個。
有沒有方式可以把定義好的MSON變成一個客制的形態?
這邊舉一個例子,假設categories
想要建立一個形態專門描述,那麽可以:
-
定義一個
Resource
叫做Data Structures
裡面有一個形態叫做Category
接下來在API Blueprint的文件 最下面增加一個區塊叫做
Data Structures
- 這是一個特殊的區塊用來定義客制形態用。在
Data Structures
下面建立一個形態叫做Category
# Data Structures ## Category + id: 1 (number, required) - 分類的Id + name: `要買` (string, required) - 分類名稱
-
修改定義回傳的時候欄位
categories
,改成回傳一個array[Category]
最後的樣子是:
+ id: 1 (number, required) - 資料的Id + title: `要買牛奶` (string, required) - todo 的描述 + state: 0 (enum) + 0 - 表示這個task已經完成 + 1 - 表示這個task已經過期 + 2 - 表示這個task尚未開始 + categories (array[Category])
從上面可以看到,
categories
從本來一個array object (預設沒有給形態就是object),變成是一個array Category。
透過這種定義客制形態,只需要定義一次,在每個地方就可以重複使用,這樣未來就算要調整,只需要改一個地方即可。
MSON:形態繼承
上面的客制形態讓我們可以重複使用一個已經定義好的形態,避免到處copy and paste。
但是很有可能有些形態很類似,只是有部分欄位不同而已,這種情況怎麽辦?
從程式的角度來説,這個時候繼承就很適合做這種事情,而剛好MSON也有支援這種方式。
假設,未來定義的api不管回傳什麽都有一個固定的格式,例如:
{
"statusDescription": "succes",
"result": {
// 看回傳内容
}
}
那麽可以用MSON的Data Structure定義出:
-
一個客制形態叫做
Success
,代表只要成功都一定要有的欄位 首先定義一個
Success
的形態,表示所有的欄位都要包含。然後建立一個
ToDoRead
的形態,繼承Success
## Success + statusDescription: succes + result ## ToDoRead (Success) + result + id: 1 (number, required) - 資料的Id + title: `要買牛奶` (string, required) - todo 的描述 + state: 0 (enum) + 0 - 表示這個task已經完成 + 1 - 表示這個task已經過期 + 2 - 表示這個task尚未開始 + categories (array[Category]) ## Category + id: 1 (number, required) - 分類的Id + name: `要買` (string, required) - 分類名稱
以上面例子來説,只要用到
ToDoRead
,就一定會有欄位statusDescription
,以及result
,因爲是繼承下來的,因此也可以覆寫。
整合到API Blueprint文件裡面 - 使用 Attributes
MSON的介紹就到了這邊,基本上上面的如果都熟悉的話,任何JSON定義都沒有什麽問題。
接下來就是要怎麽在API Blueprint裡面使用定義出來的MSON形態。
要使用很簡單,本來上一篇是直接在Response
裡面放入JSON,現在要用MSON只需要改成使用關鍵字Attributes
即可。
以今天的例子來説,最後結果會是:
### 取得單筆TODO [GET /api/todo/{todoId}]
取得單筆todo資料
+ parameters
+ todoId: 10 - todo 的id
+ Response 200 (application/json)
+ Attributes (ToDoRead)
最後在文件呈現的樣子會是:
從上面截圖可以看到,每一個欄位的描述,以及一些範例的值。
Attributes
就不需要括弧定義使用的形態,直接在下面寫上面提到的欄位定義語法即可。
結語
這一篇介紹了MSON這個語法,透過MSON不只可以定義欄位的一些描述以及形態,還可以定義出客制形態並且透過繼承方式讓形態可以重複使用。
到這邊爲止,基本上怎麽用apiary定義api就沒有什麽問題了,接下來看另外一個功能,也就是mock的功能。
寫好的文件可以讓apiary自動產生mock,讓前端可以直接串接mock開發。
下一篇([apiary][06]設計API時好用的工具 - 讓前後端溝通格式不再卡卡 - 前端如何使用mock server以及inspector來開發)來看看怎麽用apiary提供的mock。
參考資料
- MSON的官方github
- https://github.com/apiaryio/mson
- API Blueprint的官方MSON tutorial
- https://apiblueprint.org/documentation/mson/tutorial.html