express集成swagger

在使用的过程中我又发现了另一个更加好用的轮子 express-swagger-generator,这个轮子的配置更简单,使用也更加的方便,接下来就简单的介绍一下,之前的配置方式在下面:

引入 express-swagger-generator

安装

yarn add express-swagger-generator

app.js 中引用

const express = require('express');
const app = express();
const expressSwagger = require('express-swagger-generator')(app);

let options = {
    swaggerDefinition: {
        info: {
            description: 'This is a sample server',
            title: 'Swagger',
            version: '1.0.0',
        },
        host: 'localhost:3000',
        basePath: '/v1',
        produces: [
            "application/json",
            "application/xml"
        ],
        schemes: ['http', 'https'],
        securityDefinitions: {
            JWT: {
                type: 'apiKey',
                in: 'header',
                name: 'Authorization',
                description: "",
            }
        }
    },
    basedir: __dirname, //app absolute path
    files: ['./routes/**/*.js'] //Path to the API handle folder
};
expressSwagger(options)
app.listen(3000);

观察可以发现这个包的配置文件和swagger-ui的是很像的,所以可以很轻松的进行迁移,并且集成完成后就可以用更简单的jsdoc来描述接口了,这可比写yaml格式的注释不知道高到哪里去了:

/**
 * This function comment is parsed by doctrine
 * @route GET /api
 * @group foo - Operations about user
 * @param {string} email.query.required - username or email - eg: user@domain
 * @param {string} password.query.required - user's password.
 * @returns {object} 200 - An array of user info
 * @returns {Error}  default - Unexpected error
 */
exports.foo = function() {}

以下为原文:


express 作为一个 node 服务端框架,当然少不了各种的接口,我之前的项目都是通过 jdoc 样式来说明接口,但是这样的表达能力依旧略显单薄,所以这里就记录下如何在 express 框架里集成大名鼎鼎的 swagger 来规范化后端接口:

使用 jdoc 说明接口

/**
 * 设置活动状态
 * 
 * @param {String} activityId 活动ID
 * 
 * @memberof activity
 */
router.post('/setActivityNextState', (req, res) => {
    ...
})

使用 swagger 说明接口

swagger访问页面

接入过程

想在 express 里接入 swagger 需要两个包swagger-jsdocswagger-ui-express,前者将 jsdoc 格式的注释转化为 swagger 类型的 json,后者使用这个 json 生产对应的 swagger 页面,所以说,接入成功之后我们给接口写的 jsdoc 注释就会自动生成为 swagger 文档页面。

安装

yarn

yarn add swagger-jsdoc swagger-ui-express

npm

npm install swagger-jsdoc swagger-ui-express --save

引入

首先打开app.js,在let app = express()下面加上这一段代码

import swaggerUi from 'swagger-ui-express'
import swaggerJSDoc from 'swagger-jsdoc'
import path from 'path'

// 配置 swagger-jsdoc
const options = {
    definition: {
        // swagger 采用的 openapi 版本 不用改
        openapi: '3.0.0',
        // swagger 页面基本信息 自由发挥
        info: {
            title: 'Express Template',
            version: '1.0.0',
        }
    },
    // 重点,指定 swagger-jsdoc 去哪个路由下收集 swagger 注释
    apis: [ path.join(__dirname, '/router/*.js') ]
}

const swaggerSpec = swaggerJSDoc(options)

// 开放 swagger 相关接口,
app.get('/swagger.json', function(req, res) {
  res.setHeader('Content-Type', 'application/json');
  res.send(swaggerSpec);
});

// 使用 swaggerSpec 生成 swagger 文档页面,并开放在指定路由
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));

注意,这段代码里使用了import / from,请确保你的项目引入了babel等语法编译器。其中最后一行代码,那里指定了你 swagger 文档页面的路由,这时候启动项目然后访问 localhost:3000/api-docs/ 就可以看到 swagger 页面了。

一个什么接口都没有的swagger文档

给接口写文档

如果上一步你已经完成的话就说明已经集成成功了,接下来就是给每个接口写对应的 swagger 文档,格式如下:

/**
 * @swagger
 * /hello:
 *   get:
 *     tags:
 *       - 测试
 *     summary: GET 测试
 *     description: 用于测试基础 GET 请求的接口
 *     responses:
 *       200:
 *         description: 【成功】 返回 world
 */
router.get('/hello', (req, res) => {
    res.send('world')
})

找到你的接口,在它上面 @swagger 之后,这一块的注释就会被swagger-jsdoc找到并解析成对应的 yaml 文档,标准的 swagger 文档使用 yaml 格式书写。这里推荐一个 在线 swagger 编辑器

在你完成了上面的工作之后重启 express 服务就可以在 localhost:3000/api-docs/ 路由下看到你刚才写的接口了。等一下,你说你的 swagger 里还是啥都没有?看下一节。

找不到接口文档

如果你可以打开 swagger 页面,但是在接口上面无论怎么写它都不会同步到 swagger 页面里,那么就有可能是刚才app.jsoptions.apis这个属性的配置出现了问题,swagger-jsdoc服务就是根据这个属性来寻找你的接口所在文件的,这里最好使用path.join()来明确路由,js 里直接写的相对路由很坑的,只要这里生成的绝对路径可以正确指向你的路由接口所在文件,那么这个问题就自然的解决了。

封装

如果你觉得把所有的代码都写到app.js里很丑陋的话,那么恭喜你,这一小节就是为你准备的,如果你喜欢到处封装的话,那你肯定有一个config.js文件,在加上我们要封装出的swagger文件和app.js,这三个的目录关系如下:

app.js ------------ 项目入口
config.js --------- 静态配置文件
/swagger
├── index.js ------ swagger封装文件

为啥要给swagger多建一层目录,我也不知道,担心以后会有 swagger 相关的文件出现,到时候就可以直接放在这个目录下。下面是具体的代码和说明:

swagger/index.js
这里引入了两个需要的包,并从config.js中获取配置,这一块的主要内容就是文章开头的代码修改了其中的静态配置项,并封装为一个用于设置 swagger 的方法

import swaggerUi from 'swagger-ui-express'
import swaggerJSDoc from 'swagger-jsdoc'
import { swaggerConfig } from '../config'

export default function setSwagger(app) {
    const options = {
        definition: {
            openapi: swaggerConfig.openapi,
            info: {
                title: swaggerConfig.title,
                version: swaggerConfig.version
            }
        },
        apis: swaggerConfig.apis
    }

    const swaggerSpec = swaggerJSDoc(options)

    app.get('/api-docs.json', (req, res) => {
        res.setHeader('Content-Type', 'application/json')
        res.send(swaggerSpec)
    })

    app.use(swaggerConfig.routerPath, swaggerUi.serve, swaggerUi.setup(swaggerSpec))
}

config.js
这里引入了path模块,注意其中的apis属性可能会因为你项目里app.jsconfig.js的路径不同而发生变化

import path from 'path'

// swagger配置信息
export const swaggerConfig = {
    openapi: '3.0.0',
    title: 'Express Template',
    version: '1.0.0',
    apis: [
        path.join(__dirname, '/router/*.js')
    ],
    routerPath: '/api-docs'
}

app.js
封装好后直接引入对应方法,并把app当做参数传过去即可

// 引入swagger
import setSwagger from './swagger'
setSwagger(app)

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容