我最近的在做的項目是一個前後端分離的項目,前後端由不同的團隊分別開發,並且前端的進度經常領先後端。這就意味着,當前端在開發一個新功能時,API 可能還沒有準備好。不過,我們會先和後端先商議好 API Schema,然後使用 Mock 數據進行開發。
但問題也隨之而來,定義 Mock 數據並配置 mock server 真的太浪費時間了!我真的非常討厭這種沒有任何技術含量的「苦力活」。所以,只好想辦法讓生成 Mock 數據的過程「自動化」。那麼,從哪裏生成這些 Mock 數據呢?突然想到了開發時使用的 Swagger UI,它提供的 Swagger JSON 準確地定義了所有的 API Schema。因此,我們可以通過 Swagger JSON 去自動生成 Mock 數據。
本篇文章會介紹如何通過 Swagger 定義去生成 Mock 數據以及 Mock Server 的配置。主要內容包括:
- Swagger 簡介
-
通過 Swagger JSON 生成 Mock 數據
- 處理 Swagger JSON
- 生成 Mock 數據
- 生成 Mock Server 配置
本文所有代碼都在這個倉庫 swagger-faker。
Swagger 簡介
在介紹 Swagger 之前,你需要先了解一下 OpenAPI 規範。因為 Swagger 定義是基於 OpenAPI 規範的。
OpenAPI 規範(OAS)為 RESTful API 定義了一個與語言無關的標準接口,允許人和計算機發現和理解服務的功能,而無需通過訪問源代碼、文檔或開發者工具。
OpenAPI 定義大致如下:
{
"swagger": "2.0",
"info": {},
"host": "petstore.swagger.io",
"basePath": "/v2",
"tags": [],
"schemes": [],
"paths": {
"/user/logout": {
"get": {
"tags": [
"user"
],
"summary": "Logs out current logged in user session",
"description": "",
"operationId": "logoutUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
}
},
"securityDefinitions": {},
"definitions": {},
"externalDocs": {}
}
查看完整 OpenAPI 定義示例
通過上面的示例,我們可以清楚地知道,/user/logout 用於註銷當前已登錄的用户會話。它是一個 GET 請求,且不接收任何請求參數。當然,清楚地描述一個 API 意味着要定義很多東西。你可能會覺得 OpenAPI 定義寫起來有點麻煩?不用擔心,在實際工作中,我們會通過註解的方式自動生成 OpenAPI 定義。
基於 OpenAPI 定義,我們還可以完成很多事情。比如自動生成服務器和客户端代碼(Swagger Codegen)、通過交互式的 UI 來可視化服務接口(Swagger UI)等等。
通過 Swagger JSON 生成 Mock 數據
處理 Swagger JSON
要生成 Mock 數據,我們應該從 Swagger JSON 中獲取哪些內容?我從 這個 Swagger JSON 中截取了一段數據,如下所示。仔細觀察下面的內容並思考這個問題。
{
"paths": {
"/pet/findByStatus": {
"get": {
"tags": ["pet"],
"summary": "Finds Pets by status",
"description": "Multiple status values can be provided with comma separated strings",
"operationId": "findPetsByStatus",
"produces": ["application/xml", "application/json"],
"parameters": [
{
"name": "status",
"in": "query",
"description": "Status values that need to be considered for filter",
"required": true,
"type": "array",
"items": {
"type": "string",
"enum": ["available", "pending", "sold"],
"default": "available"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid status value"
}
},
"security": [
{
"petstore_auth": ["write:pets", "read:pets"]
}
]
}
}
}
}
從上面的例子中可以發現,對於一個請求來説,我們需要的 Mock 數據就是它成功響應之後的數據。也就是説,對於 Swagger JSON,我們需要關心 responses 中 HTTP Status Code 為 2xx 的數據。但是 response 可能會引用 definitions 中定義的數據。因此,為了生成 Mock 數據,我們還需要處理 $ref,也就是用 Definitions 中定義的數據替換它。
生成 Mock 數據
處理好 response 之後,就可以生成 Mock 數據了。因為 Swagger JSON 中可以為 response 或者每一個 property 定義 examples/example,所以使用 examples/example 來生成 Mock 數據一定是最準確的。因此,我們會優先使用 examples/example。如果沒有定義 examples/example,我們就通過 type 定義的數據類型去生成。
因為 faker.js 能讓我們更方便地去生成 Mock 數據,因此這裏選用了它。你可以像下面這樣,構造一些方法,去生成不同類型的假數據。
import * as faker from "faker";
export const getRandomArrayItem = (items: any[]) => items[Math.floor(Math.random() * items.length)];
export const booleanGenerator = () => faker.random.boolean();
export const stringGenerator = (enumList?: any[]) => (enumList ? getRandomArrayItem(enumList) : faker.random.words());
export const numberGenerator = (max?: number, min?: number) =>
faker.random.number({
min,
max,
});
export const fileGenerator = () => faker.system.mimeType();
生成 Mock Server 配置
除了生成 Mock 數據之外,很多時候我們還需要配置 Mock Server。就拿我們常用的 JSON Server 來説,我們還需要配置一些額外的東西。比如在 db.json 中配置路由對應的 Mock 數據,在 routes.json 中自定義路由規則等。
因此,我們還需要從 response 中獲取更多的內容,包括 path、basePath、method、response 和 queryParams,如下所示:
{
"path": "/pet/findByStatus",
"basePath": "/v2",
"method": "get",
"response": [
{
"id": 93645,
"category": {
"id": 85609,
"name": "open-source"
},
"name": "doggie",
"photoUrls": ["firewall Berkshire withdrawal"],
"tags": [
{
"id": 13201,
"name": "Salad synthesize e-business"
}
],
"status": "pending"
}
],
"queryParams": ["status"]
}
生成 JSON Server 中的自定義路由時,我們可以根據規則,使用 basePath, path 和 queryParams 拼接即可。
// routes.json
{
"/v2/pet/findByStatus?status=:status": "./findPetsByStatus"
}
最後,將這些數據寫入對應的文件中便大功告成了。
最後
生成 Mock 數據的過程中還是有很多細節需要處理,感興趣的同學可以去這個倉庫 swagger-faker 查看源碼。