摘要:中基于的自動實(shí)體類構(gòu)建與接口文檔生成是筆者對于開源項(xiàng)目的描述,對于不反感使用注解的項(xiàng)目中利用添加合適的實(shí)體類或者接口類注解,從而實(shí)現(xiàn)支持嵌套地實(shí)體類校驗(yàn)與生成等模型生成基于的接口文檔生成等等功能。
swagger-decorator: 一處注解,多處使用JavaScript 中基于 swagger-decorator 的自動實(shí)體類構(gòu)建與 Swagger 接口文檔生成是筆者對于開源項(xiàng)目 swagger-decorator 的描述,對于不反感使用注解的項(xiàng)目中利用 swagger-decorator 添加合適的實(shí)體類或者接口類注解,從而實(shí)現(xiàn)支持嵌套地實(shí)體類校驗(yàn)與生成、Sequelize 等 ORM 模型生成、基于 Swagger 的接口文檔生成等等功能。如果有對 JavaScript 語法使用尚存不明的可以參考 JavaScript 學(xué)習(xí)與實(shí)踐資料索引或者現(xiàn)代 JavaScript 開發(fā):語法基礎(chǔ)與實(shí)踐技巧系列文章。
swagger-decorator 的初衷是為了簡化 JavaScript 應(yīng)用開發(fā),筆者在編寫 JavaScript 應(yīng)用(Web 前端 & Node.js)時(shí)發(fā)現(xiàn)我們經(jīng)常需要重復(fù)地創(chuàng)建實(shí)體類、添加注釋或者進(jìn)行類型校驗(yàn),swagger-decorator 希望能夠讓開發(fā)者一處注解、多處使用。需要強(qiáng)調(diào)的是,在筆者多年的 Java 應(yīng)用開發(fā)中也感受到,過多過度的注解反而會大大削弱代碼的可讀性,因此筆者也建議應(yīng)該在合適的時(shí)候舒心地使用
swagger-decorator,而不是本末倒置,一味地追求注解覆蓋率。swagger-decorator 已經(jīng)可以用于實(shí)體類生成與校驗(yàn)、Sequelize ORM 實(shí)體類生成、面向 Koa 的路由注解與 Swagger 文檔自動生成。我們可以使用 yarn 或者 npm 安裝 swagger-decorator 依賴,需要注意的是,因?yàn)槲覀冊陂_發(fā)中還會用到注解語法,因此還需要添加 babel-plugin-transform-decorators-legacy 插件以進(jìn)行語法兼容轉(zhuǎn)化。
# 使用 npm 安裝依賴 $ npm install swagger-decorator -S $ # 使用 yarn 安裝依賴 $ yarn add swagger-decorator $ yarn add babel-plugin-transform-decorators-legacy -D # 導(dǎo)入需要的工具函數(shù) import { wrappingKoaRouter, entityProperty, ... } from "swagger-decorator";實(shí)體類注解
swagger-decorator 的核心 API 即是對于實(shí)體類的注解,該注解不會改變實(shí)體類的任何屬性表現(xiàn),只是會將注解限定的屬性特性記錄在內(nèi)置的 innerEntityObject 單例中以供后用。屬性注解 entityProperty 的方法說明如下:
/** * Description 創(chuàng)建某個(gè)屬性的描述 * @param type 基礎(chǔ)類型 self - 表示為自身 * @param description 描述 * @param required 是否為必要參數(shù) * @param defaultValue 默認(rèn)值 * @param pattern * @param primaryKey 是否為主鍵 * @returns {Function} */ export function entityProperty({ // 生成接口文檔需要的參數(shù) type = "string", description = "", required = false, defaultValue = undefined, // 進(jìn)行校驗(yàn)所需要的參數(shù) pattern = undefined, // 進(jìn)行數(shù)據(jù)庫連接需要的參數(shù) primaryKey = false }) {}
簡單的用戶實(shí)體類注解如下,這里的數(shù)據(jù)類型 type 支持 Swagger 默認(rèn)的字符格式的類型描述,也支持直接使用 JavaScript 類名或者 JavaScript 數(shù)組。
// @flow import { entityProperty } from "../../src/entity/decorator"; import UserProperty from "./UserProperty"; /** * Description 用戶實(shí)體類 */ export default class User { // 編號 @entityProperty({ type: "integer", description: "user id, auto-generated", required: true }) id: string = 0; // 姓名 @entityProperty({ type: "string", description: "user name, 3~12 characters", required: false }) name: string = "name"; // 郵箱 @entityProperty({ type: "string", description: "user email", pattern: "email", required: false }) email: string = "email"; // 屬性 @entityProperty({ type: UserProperty, description: "user property", required: false }) property: UserProperty = new UserProperty(); } export default class UserProperty { // 朋友列表 @entityProperty({ type: ["number"], description: "user friends, which is user ids", required: false }) friends: [number]; }
Swagger 內(nèi)置數(shù)據(jù)類型定義:
Common Name | type | format | Comments |
---|---|---|---|
integer | integer | int32 | signed 32 bits |
long | integer | int64 | signed 64 bits |
float | number | float | |
double | number | double | |
string | string | ||
byte | string | byte | base64 encoded characters |
binary | string | binary | any sequence of octets |
boolean | boolean | ||
date | string | date | As defined by full-date - RFC3339 |
dateTime | string | date-time | As defined by date-time - RFC3339 |
password | string | password | Used to hint UIs the input needs to be obscured. |
實(shí)體類定義完畢之后,我們首先可以使用 instantiate 函數(shù)為實(shí)體類生成實(shí)例;不同于直接使用 new 關(guān)鍵字創(chuàng)建,instantiate 能夠根據(jù)指定屬性的數(shù)據(jù)類型或者格式進(jìn)行校驗(yàn),同時(shí)能夠迭代生成嵌套地子對象。
/** * Description 從實(shí)體類中生成對象,并且進(jìn)行數(shù)據(jù)校驗(yàn);注意,這里會進(jìn)行遞歸生成,即對實(shí)體類對象同樣進(jìn)行生成 * @param EntityClass 實(shí)體類 * @param data 數(shù)據(jù)對象 * @param ignore 是否忽略校驗(yàn) * @param strict 是否忽略非預(yù)定義類屬性 * @throws 當(dāng)校驗(yàn)失敗,會拋出異常 */ export function instantiate( EntityClass: Function, data: { [string]: any }, { ignore = false, strict = true }: { ignore: boolean, strict: boolean } = {} ): Object {}
這里為了方便描述使用 Jest 測試用例說明不同的使用場景:
describe("測試實(shí)體類實(shí)例化函數(shù)", () => { test("測試 User 類實(shí)例化校驗(yàn)", () => { expect(() => { instantiate(User, { name: "name" }).toThrowError(/validate fail!/); }); let user = instantiate(User, { id: 0, name: "name", email: "a@q.com" }); // 判斷是否為 User 實(shí)例 expect(user).toBeInstanceOf(User); }); test("測試 ignore 參數(shù)可以允許忽略校驗(yàn)", () => { instantiate( User, { name: "name" }, { ignore: true } ); }); test("測試 strict 參數(shù)可以控制是否忽略額外參數(shù)", () => { let user = instantiate( User, { name: "name", external: "external" }, { ignore: true, strict: true } ); expect(user).not.toHaveProperty("external", "external"); user = instantiate( User, { name: "name", external: "external" }, { ignore: true, strict: false } ); expect(user).toHaveProperty("external", "external"); }); }); describe("測試嵌套實(shí)例生成", () => { test("測試可以遞歸生成嵌套實(shí)體類", () => { let user = instantiate(User, { id: 0, property: { friends: [0] } }); expect(user.property).toBeInstanceOf(UserProperty); }); });Sequelize 模型生成
Sequelize 是 Node.js 應(yīng)用中常用的 ORM 框架,swagger-decorator 提供了 generateSequelizeModel 函數(shù)以方便從實(shí)體類中利用現(xiàn)有的信息生成 Sequelize 對象模型;generateSequelizeModel 的第一個(gè)參數(shù)輸入實(shí)體類,第二個(gè)參數(shù)輸入需要覆寫的模型屬性,第三個(gè)參數(shù)設(shè)置額外屬性,譬如是否需要將駝峰命名轉(zhuǎn)化為下劃線命名等等。
const originUserSequelizeModel = generateSequelizeModel( User, { _id: { primaryKey: true } }, { mappingCamelCaseToUnderScore: true } ); const UserSequelizeModel = sequelize.define( "b_user", originUserSequelizeModel, { timestamps: false, underscored: true, freezeTableName: true } ); UserSequelizeModel.findAll({ attributes: { exclude: [] } }).then(users => { console.log(users); });從 Flow 類型聲明中自動生成注解
筆者習(xí)慣使用 Flow 作為 JavaScript 的靜態(tài)類型檢測工具,因此筆者添加了 flowToDecorator 函數(shù)以自動地從 Flow 聲明的類文件中提取出類型信息;內(nèi)部原理參考現(xiàn)代 JavaScript 開發(fā):語法基礎(chǔ)與實(shí)踐技巧 一書中的 JavaScript 語法樹與代碼轉(zhuǎn)化章節(jié)。該函數(shù)的使用方式為:
// @flow import { flowToDecorator } from "../../../../src/transform/entity/flow/flow"; test("測試從 Flow 中提取出數(shù)據(jù)類型并且轉(zhuǎn)化為 Swagger 接口類", () => { flowToDecorator("./TestEntity.js", "./TestEntity.transformed.js").then( codeStr => { console.log(codeStr); }, err => { console.error(err); } ); });
這里對應(yīng)的 TestEntity 為:
// @flow import AnotherEntity from "./AnotherEntity"; class Entity { // Comment stringProperty: string = 0; classProperty: Entity = null; rawProperty; @entityProperty({ type: "string", description: "this is property description", required: true }) decoratedProperty; }
轉(zhuǎn)化后的實(shí)體類為:
// @flow import { entityProperty } from "swagger-decorator"; import AnotherEntity from "./AnotherEntity"; class Entity { // Comment @entityProperty({ type: "string", required: false, description: "Comment" }) stringProperty: string = 0; @entityProperty({ type: Entity, required: false }) classProperty: Entity = null; @entityProperty({ type: "string", required: false }) rawProperty; @entityProperty({ type: "string", description: "this is property description", required: true }) decoratedProperty; }接口注解與 Swagger 文檔生成
對于 Swagger 文檔規(guī)范可以參考 OpenAPI Specification ,而對于 swagger-decorator 的實(shí)際使用可以參考本項(xiàng)目的使用示例或者 基于 Koa2 的 Node.js 應(yīng)用模板 。
封裝路由對象import { wrappingKoaRouter } from "swagger-decorator"; ... const Router = require("koa-router"); const router = new Router(); wrappingKoaRouter(router, "localhost:8080", "/api", { title: "Node Server Boilerplate", version: "0.0.1", description: "Koa2, koa-router,Webpack" }); // define default route router.get("/", async function(ctx, next) { ctx.body = { msg: "Node Server Boilerplate" }; }); // use scan to auto add method in class router.scan(UserController);定義接口類
export default class UserController extends UserControllerDoc { @apiRequestMapping("get", "/users") @apiDescription("get all users list") static async getUsers(ctx, next): [User] { ctx.body = [new User()]; } @apiRequestMapping("get", "/user/:id") @apiDescription("get user object by id, only access self or friends") static async getUserByID(ctx, next): User { ctx.body = new User(); } @apiRequestMapping("post", "/user") @apiDescription("create new user") static async postUser(): number { ctx.body = { statusCode: 200 }; } }
在 UserController 中是負(fù)責(zé)具體的業(yè)務(wù)實(shí)現(xiàn),為了避免過多的注解文檔對于代碼可讀性的干擾,筆者建議是將除了路徑與描述之外的信息放置到父類中聲明;swagger-decorator 會自動從某個(gè)接口類的直接父類中提取出同名方法的描述文檔。
export default class UserControllerDoc { @apiResponse(200, "get users successfully", [User]) static async getUsers(ctx, next): [User] {} @pathParameter({ name: "id", description: "user id", type: "integer", defaultValue: 1 }) @queryParameter({ name: "tags", description: "user tags, for filtering users", required: false, type: "array", items: ["string"] }) @apiResponse(200, "get user successfully", User) static async getUserByID(ctx, next): User {} @bodyParameter({ name: "user", description: "the new user object, must include user name", required: true, schema: User }) @apiResponse(200, "create new user successfully", { statusCode: 200 }) static async postUser(): number {} }運(yùn)行應(yīng)用
run your application and open swagger docs (PS. swagger-decorator contains Swagger UI):
/swagger
/swagger/api.json
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/84093.html
摘要:注解方式為應(yīng)用動態(tài)生成文檔目前我司服務(wù)端應(yīng)用程序框架主要采用了與,而因?yàn)榻衲暧泻芏嗟恼{(diào)研階段的產(chǎn)品線發(fā)布,持續(xù)部署接口文檔以及線上質(zhì)量監(jiān)控這三個(gè)問題愈發(fā)突出。 swagger-decorator:注解方式為 Koa2 應(yīng)用自動生成 Swagger 文檔 從屬于筆者的服務(wù)端應(yīng)用程序開發(fā)與系統(tǒng)架構(gòu),記述了如何在以 Koa2 與 koa-router 開發(fā)服務(wù)端應(yīng)用時(shí),通過自定義 swagg...
摘要:前端日報(bào)精選常用實(shí)例的實(shí)現(xiàn)與封裝實(shí)現(xiàn)一個(gè)構(gòu)建基于的可擴(kuò)展應(yīng)用規(guī)范翻譯從到中文開源中國兩級緩存實(shí)踐掘金中基于的自動實(shí)體類構(gòu)建與接口文檔生成某熊的全棧之路繼承總結(jié)教程中的五種組件形式掘金再說的問題前端開發(fā)前端每周清單第期正式 2017-07-18 前端日報(bào) 精選 javascript常用實(shí)例的實(shí)現(xiàn)與封裝實(shí)現(xiàn)一個(gè) SwiperRekit 2.0 構(gòu)建基于React+Redux+React-r...
摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。對該漏洞的綜合評級為高危。目前,相關(guān)利用方式已經(jīng)在互聯(lián)網(wǎng)上公開,近期出現(xiàn)攻擊嘗試爆發(fā)的可能。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開發(fā)教程、工程實(shí)踐、深度閱讀、開源項(xiàng)目、巔峰人生等欄目。歡...
摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。背后的故事本文是對于年之間世界發(fā)生的大事件的詳細(xì)介紹,闡述了從提出到角力到流產(chǎn)的前世今生。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開發(fā)教程、工程實(shí)踐、深度閱讀、開源項(xiàng)目、巔峰人生等欄目。歡迎...
摘要:前言目前互聯(lián)網(wǎng)開發(fā)市場都流行前后臺真正的分離,后臺提供數(shù)據(jù)接口,前臺負(fù)責(zé)請求數(shù)據(jù)并渲染。今天就介紹一款將接口文檔編寫和測試合并一起的集大成者,也是目前很多企業(yè)再用的一個(gè)管理工具。 前言:目前互聯(lián)網(wǎng)開發(fā)市場都流行前后臺真正的分離,后臺提供數(shù)據(jù)API接口,前臺負(fù)責(zé)請求數(shù)據(jù)并渲染。那么我們程序猿們在編寫接口的時(shí)候,最不方便之處就是寫完接口后需要進(jìn)行文檔的編寫以及接口的測試。今天就介紹一款將接...
閱讀 2838·2021-09-10 10:50
閱讀 2196·2019-08-29 16:06
閱讀 3199·2019-08-29 11:02
閱讀 1100·2019-08-26 14:04
閱讀 2810·2019-08-26 13:24
閱讀 2304·2019-08-26 12:16
閱讀 551·2019-08-26 10:29
閱讀 3098·2019-08-23 18:33