从零开始的野路子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文件写长了真是需要游标卡尺……):

openapi: 3.0.0
info:
  title: Work with Swagger
  description: This is just an experiment
  version: v1.0

servers:
- url: http://localhost:5000

paths:
  /:
    get:
      summary: Health check endpoint
      operationId: healthCheck
      responses:
        200:
          description: Successful operation
        400:
          description: Bad request
        404:
          description: Not found

  /age:
    get:
      summary: Set the age of the user
      parameters:
      - name: number
        in: query
        description: The age of the user
        required: true
        schema:
          type: integer
          format: int64
      responses:
        200:
          description: Successful operation
        400:
          description: Bad request
        404:
          description: Not found

  /tricks:
    post:
      summary: Hit by some tricks
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/tricks'
      responses:
        200:
          description: Successful operation
        400:
          description: Bad request
        404:
          description: Not found

components:
  schemas:
    tricks:
      type: object
      required:
      - tricks
      - comment
      properties:
        tricks:
          type: array
        comment:
          type: string

 

这里我们对每个路由节点做出了一些规定,比如对于/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

 

posted @ 2020-11-18 20:09  SilenceGTX  阅读(566)  评论(0编辑  收藏  举报