swagger-decorator:註解方式為 Koa2 應用動態生成 Swagger 文檔-知乎專欄
swagger-decorator:註解方式為 Koa2 應用自動生成 Swagger 文檔從屬於筆者的服務端應用程序開發與系統架構,記述了如何在以 Koa2 與 koa-router 開發服務端應用時,通過自定義 swagger-decorator 庫來實現類 Spring-Boot 中註解方式動態生成 Swagger 標準的介面文檔。
swagger-decorator:註解方式為 Koa2 應用動態生成 Swagger 文檔
目前我司服務端應用程序框架主要採用了 Java Spring 與 Node.js,而因為今年有很多的調研階段的產品線 Demo 發布,持續部署、介面文檔以及線上質量監控這三個問題愈發突出。本文則主要針對介面文檔的實時發布進行一些探討;在前後端分離的今天,即使是由單人縱向負責某個業務流,也需要將前後端交互的介面規範清晰地定義並且發布,以保證項目的透明性與可維護性。理想的開發流程中,應當在產品設計階段確定好關鍵欄位命名、資料庫表設計以及介面文檔;不過實際操作中往往因為業務的多變性以及人手的缺失,使得介面的定義並不能總是實時地在項目成員之間達成一致。如果要讓開發人員在更改介面的同時花費額外精力維護一份開發文檔,可能對於我司這樣的小公司而言存在著很大的代價與風險。軟體開發中存在著所謂 Single Source of Truth 的原則,我們也需要盡量避免文檔與實際實現的不一致造成的團隊內矛盾以及無用的付出。綜上所述,我們希望能夠在編寫後台代碼、添加註釋的同時,能夠自動地生成介面文檔;筆者比較熟悉 Spring 中以註解方式添加 Swagger 文檔的模式,不過 Java 庫的抽象程度一般較高,用起來也不怎麼順手。筆者在編寫我司node-server-boilerplate根據自己的想法設計了swagger-decorator。此外,項目中使用 Flow 進行靜態類型檢測,並且遵循我司內部的JavaScript 編程樣式指南。
我們可以使用 npm 或者 yarn 安裝 swagger-decorator,需要注意的是,因為使用了註解,因此建議是配置 Webpack 與 Babel,不熟悉的同學可以直接參考node-server-boilerplate:
$ yarn add swagger-decorator # 依賴於 Babel 的 transform-decorators-legacy 轉換插件來使用 Decorator $ yarn add transform-decorators-legacy -D
安裝完畢之後,我們需要對項目中使用的路由進行封裝。目前筆者只是針對 koa-router 中的路由對象進行封裝,未來若有必要可以針對其他框架的路由解決方案進行封裝。我們首先需要做的就是在路由定義之前使用 wrappingKoaRouter 函數修飾 router 對象:
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" }); //定義默認的根路由 router.get("/", async function(ctx, next) { ctx.body = { msg: "Node Server Boilerplate" }; }); //定義用戶處理路由 router.scan(UserController);
該函數的參數說明如下,對於 info 的結構參考這裡:
/** * Description 將 router 對象的方法進行封裝 * @param router 路由對象 * @param host API 域名 * @param basePath API 基本路徑 * @param info 其他的 Swagger 基本信息 */ export function wrappingKoaRouter( router: Object, host: string = "localhost", basePath: string = "", info: Object = {} ) {}
值得一提的是,在封裝 router 時,筆者自定義了 scan 方法,其能夠根據自動遍歷目標類中的自定義方法,有點類似於 Java 中的 ComponentScan:
/** * Description 掃描某個類中的所有靜態方法,按照其註解將其添加到 * @param staticClass */ router.scan = function(staticClass: Function) { let methods = Object.getOwnPropertyNames(staticClass); // 移除前三個屬性 constructor、name methods.shift(); methods.shift(); methods.shift(); for (let method of methods) { router.all(staticClass[method]); } };
準備工作完成之後,我們即可以開始定義具體的介面控制器;筆者不喜歡過多的封裝,因此這裡選用了類的靜態方法來定義具體的介面函數,整個 Controller 也只是樸素函數。下面筆者列舉了常見的獲取全部用戶列表、根據用戶編號獲取用戶詳情、創建新用戶這幾個介面的文檔注釋方式:
import { apiDescription, apiRequestMapping, apiResponse, bodyParameter, pathParameter, queryParameter } from "swagger-decorator"; import User from "../entity/User"; /** * Description 用戶相關控制器 */ export default class UserController { @apiRequestMapping("get", "/users") @apiDescription("get all users list") @apiResponse(200, "get users successfully", [User]) static async getUsers(ctx, next): [User] { ... } @apiRequestMapping("get", "/user/:id") @apiDescription("get user object by id, only access self or friends") @pathParameter({ name: "id", description: "user id", type: "integer" }) @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 { ... } @apiRequestMapping("post", "/user") @apiDescription("create new user") @bodyParameter({ name: "user", description: "the new user object, must include user name", required: true, schema: User }) @apiResponse(200, "create new user successfully", { status_code: "200" }) static async postUser(): number { ... } }
在對介面註解的時候,我們需要用實體類指明返回值或者請求體中包含的參數信息,因此我們也需要使用 swagger-decorator 提供的 entityProperty 註解來為實體類添加描述。值得一提的是,這裡我們支持直接將 Object 作為描述對象的返回值,算是避免了 Java 中的一大痛點。
// @flow import { entityProperty } from "swagger-decorator"; /** * Description 用戶實體類 */ export default class User { // 編號 @entityProperty({ type: "integer", description: "user id, auto-generated", required: false }) id: string = 0; // 姓名 @entityProperty({ type: "string", description: "user name, 3~12 characters", required: true }) name: string = "name"; // 朋友列表 friends: [number] = [1]; // 屬性 properties: { address: string } = { address: "address" }; }
對於沒有添加註解的屬性,swagger-decorator 會自動根據其默認值來推測類型。然後我們就可以正常地啟動應用,swagger-decorator 已經自動地為 router 對象添加了兩個路由,其中 /swagger 指向了 Swagger UI:
而 /swagger/api.json 指向了 Swagger 生成的 JSON 文檔:
歡迎有興趣的朋友提出 ISSUE、指導意見或者希望納入的特性。
※亞馬遜137億美元收購全食超市 探路線上線下協同
※聽聞麒麟970上了寒武紀
※這個來自新加坡的團隊發出了一項挑戰,你敢接受嗎?
※輕桌面 2.0,顏值外觀黨的桌面生活分享
TAG:推酷 |
※使用gradle生成Spring Boot應用的Docker Image
※Gradle Kotlin DSL的accessors 生成問題
※WordPress怎麼生成sitemap.xml?插件XML Sitemap & Google News
※Regenerate Thumbnails讓WordPress重新生成特色圖像更簡單
※mysql8+mybatis-plus3.1自動生成lombok和swagger和增刪改查介面
※「python」生成器的高級應用send、close和throw方法
※NetCore2.1 WebAPI 根據swagger.json自動生成客戶端代碼
※rapid-generator自動生成代碼步驟
※SpringMVC,Spring,Hibernate框架自動生成器
※TensorFlow官方力推、GitHub爆款項目:用Attention模型自動生成圖像字幕
※Mybatis+velocity自動生成代碼
※CodeWarrior IDE使用Tips-使用burner將elf文件轉換生成HEX和BIN文件的方法和步驟詳解
※4月Feelreal將為氣味生成面具再次開啟Kickstarter眾籌
※LeaFlet學習之結合turf.js生成簡單的等值線demo
※Additive Works推出用於生成3D列印支撐的新Amphyon模塊
※基於 Tensorflow eager 的文本生成,注意力,圖像注釋的完整代碼
※使用以 Tensorflow 為後端的 Keras 構建生成對抗網路的代碼示例
※python機器學習庫sklearn——生成樣本數據
※靜態站點生成器:makesite.py
※DeepMind 最新Science論文:生成查詢網路GQN