从零开始的野路子React/Node(7)将Swagger(OpenAPI)运用于后端API
之前公司做项目是用过swagger来配置python模型的API,感觉非常好用。swagger可以提供request, response甚至error的验证机制,十分便利。node当然也可以用啦。
我们需要使用的库主要是swagger-ui-express,它将提供swagger的相关功能以及一个UI,方便查看和调试。
1、初始设定
老规矩,我们还是通过express work_with_swagger来新建一个叫work_with_swagger的项目。然后依旧是删除bin文件夹,改改app.js以及将package.json中的start改为node app.js(当然,用nodemon会更好,可以安装npm install nodemon,然后将start改为nodemon app.js)。
var express = require('express'); var app = express(); app.use(express.urlencoded({extended: true})); //解析json用 app.use(express.json()); //解析json用 app.listen(5000, function() { console.log('App listening on port 5000...') });
然后我们来做些设置:
我们会有一个Controller来负责request -> response的逻辑。
我们将原来的routes删掉,增加自己的路由Routes,对接到对应的controller。
我们添加一个swagger文件夹,并在其中加入我们的配置文件swagger.yml。
2、添加swagger-ui-express
现在,我们需要改动一下app.js来把swagger配置文件包含进去。由于我们的swagger文件是yaml文件,所以我们需要yamljs库来读取它(默认只能读取json格式的swagger文件,直接抄https://www.npmjs.com/package/swagger-ui-express提供的方法)。
此外,我们把路由文件也加入进去。
var express = require('express'); var swaggerUi = require('swagger-ui-express'); var YAML = require('yamljs'); const swaggerDocument = YAML.load('./swagger/swagger.yml'); const RandomRouter = require('./Routes/RandomRouter'); var app = express(); app.use(express.urlencoded({extended: true})); //解析json用 app.use(express.json()); //解析json用 app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); app.use('/', RandomRouter) app.listen(5000, function() { console.log('App listening on port 5000...') });
我们现在可以象征性地写几个controllers并把他们加入路由文件中,2个get,1个post:
var express = require('express'); var YAML = require('yamljs'); exports.healthCheck = (req, res) => { const swaggerDocument = YAML.load('./swagger/swagger.yml'); res.status(200).send( { message:'耗子尾汁', version:swaggerDocument['info']['version'] } ) }; exports.setAge = (req, res) => { console.log(req) var age = req.query.number res.status(200).send(`来骗,来偷袭,我${age}岁的老同志`) }; exports.tricks = (req, res) => { var tricks = req.body.tricks var comment = req.body.comment var line = tricks.join(', ') + ', ' + comment res.status(200).send(line) };
var express = require('express'); const RandomController = require('../Controllers/RandomController'); var router = express.Router(); router.get('/age', RandomController.setAge); router.post('/tricks', RandomController.tricks); router.get('/', RandomController.healthCheck); module.exports = router;
接下来,我们来配置一下swagger.yml(yaml文件写长了真是需要游标卡尺……):
这里我们对每个路由节点做出了一些规定,比如对于/age,我们规定query中传入的参数number只能是整数;比如对于/tricks,传入的json一定要包含tricks和comment等等(也就是规定了schema)。
这里我们可以用2种不同的方式来规定schema:一种是直接在节点部分的schema下继续下写去(例如/age节点那样);另一种是单独写在components的schemas下面,而在节点的schema处用$ref来指定引用(例如/tricks节点那样)。
OK,差不多完工了,现在我们进入UI界面看一看效果,输入http://localhost:5000/api-docs/,会出现这样一个界面:
点开某个节点(此处为/age/{number}),就能看到我们对该节点的一些设置:
点击Try it out之后就可以输入query,我们输入一个整数试试,点击Execute:
如果我们试图输入string,会发现无法Execute:
看来效果不错。但swagger-ui-express毕竟只是类似于一个文档工具,点到为止。我们在Postman中试试,会发现其实根本没有验证机制的存在……
3、补上验证机制
虽然验证要以和为贵,但不能光点到为止啊,看来我们还需要另一个验证工具,那就是openapi-express-validator。
我们用npm install openapi-express-validator来完成安装,然后再在app.js中加入一些内容:
var express = require('express'); var swaggerUi = require('swagger-ui-express'); var YAML = require('yamljs'); var OpenApiValidator = require('express-openapi-validator'); const swaggerDocument = YAML.load('./swagger/swagger.yml'); const RandomRouter = require('./Routes/RandomRouter'); var app = express(); app.use(express.urlencoded({extended: true})); //解析json用 app.use(express.json()); //解析json用 app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // 新增,指定一下swagger文件 const spec = './swagger/swagger.yml'; app.use('/spec', express.static(spec)); // 将OpenApiValidator加入中间件 app.use( OpenApiValidator.middleware({ apiSpec: './swagger/swagger.yml', validateRequests: true, //validateResponses: true, // 如果需要验证response,则设为true }), ); app.use('/', RandomRouter) app.use((err, req, res, next) => { // 配置错误信息 res.status(err.status || 500).json({ message: err.message, errors: err.errors, }); }); app.listen(5000, function() { console.log('App listening on port 5000...') });
现在我们再来试试:
这次没问题了,我们得到了一个错误信息,提示我们params中的number应该是整数。
输入整数则没有问题,验证功能完成了。
代码见:
https://github.com/SilenceGTX/work_with_swagger