我最近的在作的項目是一個先後端分離的項目,先後端由不一樣的團隊分別開發,而且前端的進度常常領前後端。這就意味着,當前端在開發一個新功能時,API 可能尚未準備好。不過,咱們會先和後端先商議好 API Schema,而後使用 Mock 數據進行開發。前端
但問題也隨之而來,定義 Mock 數據並配置 mock server 真的太浪費時間了!我真的很是討厭這種沒有任何技術含量的「苦力活」。因此,只好想辦法讓生成 Mock 數據的過程「自動化」。那麼,從哪裏生成這些 Mock 數據呢?忽然想到了開發時使用的 Swagger UI,它提供的 Swagger JSON 準確地定義了全部的 API Schema。所以,咱們能夠經過 Swagger JSON 去自動生成 Mock 數據。git
本篇文章會介紹如何經過 Swagger 定義去生成 Mock 數據以及 Mock Server 的配置。主要內容包括:github
經過 Swagger JSON 生成 Mock 數據json
本文全部代碼都在這個倉庫 swagger-faker。後端
在介紹 Swagger 以前,你須要先了解一下 OpenAPI 規範。由於 Swagger 定義是基於 OpenAPI 規範的。服務器
OpenAPI 規範(OAS)爲 RESTful API 定義了一個與語言無關的標準接口,容許人和計算機發現和理解服務的功能,而無需經過訪問源代碼、文檔或開發者工具。
OpenAPI 定義大體以下:session
{ "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": {} }
經過上面的示例,咱們能夠清楚地知道,/user/logout 用於註銷當前已登陸的用戶會話。它是一個 GET 請求,且不接收任何請求參數。固然,清楚地描述一個 API 意味着要定義不少東西。你可能會以爲 OpenAPI 定義寫起來有點麻煩?不用擔憂,在實際工做中,咱們會經過註解的方式自動生成 OpenAPI 定義。前後端分離
基於 OpenAPI 定義,咱們還能夠完成不少事情。好比自動生成服務器和客戶端代碼(Swagger Codegen)、經過交互式的 UI 來可視化服務接口(Swagger UI)等等。dom
要生成 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 中定義的數據替換它。
處理好 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 數據以外,不少時候咱們還須要配置 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 查看源碼。