node从入门到放弃系列之(8)koa2 swaggerUI的使用

奉上代码: node服务demo代码=》koa2-server项目代码;vue前端demo代码=》 vue-client项目代码
如果git登不上可以换gitee=》koa2-server项目代码;vue前端demo代码=》 vue-client项目代码

node的swagger现在也用上了注释型的文档,和java的有点类似。主要步骤就两个:swagger配置和注释生成文档

swagger配置

需要用到的依赖koa2-swagger-uiswagger-jsdoc,使用的都是4.0.0版本的


// koa2-swagger-ui UI视图组件  swagger-jsdoc 识别写的 /***/ 转 json
npm install koa2-swagger-ui swagger-jsdoc --save

在根目录下config文件夹里新建swagger.js
详细js文件地址=》swagger配置

const router = require('koa-router')(); // 引入路由函数
const path = require('path');
const swaggerJSDoc = require('swagger-jsdoc');
const swaggerDefinition = {
    info: {
    description:
      'This is a sample server Koa2 server.  You can find out more about     Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).      For this sample, you can use the api key `special-key` to test the authorization     filters.',
    version: '1.0.0',
    title: 'Koa2_server Swagger',
    // 服务条款
    // termsOfService: 'http://swagger.io/terms/',
    contact: {
      name: 'Contact developers',
      url: 'https://mail.qq.com/',
      email: '741167479@qq.com'
    },
    // 开源协议
    license: {
      name: 'Apache 2.0',
      url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
    }
  },
  host: 'localhost:4000',
  basePath: '/', // Base path (optional), host/basePath
  schemes: ['http', 'https'],
  securityDefinitions: {
    server_auth: {
      type: 'oauth2',
      description: '登录账号密码鉴权',
      tokenUrl: 'http://localhost:4000/image/oauth',
      flow: 'password',
      scopes: {
        token: 'modify pets in your account'
      }
    },
    token: {
      type: 'apiKey',
      name: 'token',
      in: 'header'
    }
  }
};
const options = {
  swaggerDefinition,
  // 写有注解的router的存放地址(当你新增swagger时文档里没显示出来的话那么就是这边地址没有加进去)
  apis: ['./routes/*.js', './routes/image/*.js'] // routes下所有的js文件和routes/image下所有js文件
};
const swaggerSpec = swaggerJSDoc(options);
// 通过路由获取生成的注解文件
router.get('/swagger.json', async ctx => {
  ctx.set('Content-Type', 'application/json');
  ctx.body = swaggerSpec;
});

module.exports = router;
// 将页面暴露出去

在项目入口app.js里引用配置信息

// swagger配置
const swagger = require('./config/swagger');
app.use(swagger.routes(), swagger.allowedMethods());
app.use(
  koaSwagger({
    routePrefix: '/swagger', // host at /swagger instead of default /docs
    swaggerOptions: {
      url: '/swagger.json' // example path to json
    }
  })
);

配置完后打开http://localhost:4000/swagger就能看到这个页面,这就说明配置是成功的,接下来就是注释接口信息,产生swagger文档了
在这里插入图片描述

注释生成文档

swagger-jsdoc enables you to integrate Swagger using JSDoc comments in your code. Just add @swagger on top of your 
DocBlock and declare themeaning of your code in YAML complying to the OpenAPI specification. If you prefer to keep 
some parts of your specification aside your code in order to keep it lighter/cleaner, you can also pass these parts 
as separate input YAML files.

这是swagger-jsdoc上给的提示,从提示中知道注释可以参考OpenAPI规范,那我就找到了一个openAPI的文档=》editor swagger,依葫芦画瓢的试了一下。
下面就以鉴权模块的几个接口的注释来详细说明下open API的使用。详细js文件地址=》鉴权模块

/**
 * @swagger
 * /security/login: # 接口地址
 *   post: # 请求体
 *     description: 用户登入 # 接口信息
 *     tags: [用户鉴权模块] # 模块名称
 *     produces: 
 *       - application/x-www-form-urlencoded # 响应内容类型
 *     parameters: # 请求参数
 *       - name: password
 *         description: 用户密码
 *         in: formData # 参数的位置,可能的值有 "query", "header", "path" 或 "cookie" 没有formData,但是我加了不报错
 *         required: true
 *         type: string
 *       - name: name
 *         description: 用户名
 *         in: formData
 *         required: true
 *         type: string # 可能的值有string、number、file(文件)等
 *     responses:
 *       '200':
 *         description: Ok
 *         schema: # 返回体说明
 *           type: 'object'
 *           properties:
 *             code:
 *               type: 'number'
 *             data:
 *               type: 'object'
 *               description: 返回数据
 *             message:
 *               type: 'string'
 *               description: 消息提示
 *       '400':
 *         description: 请求参数错误
 *       '404':
 *         description: not found
 */
router.post('/login', async (ctx, next) => {
  const requestParam = ['name', 'password'];
  const user = ctx.request.body;
  console.log(user);
  if (paramCheck.check(user, requestParam) !== true) {
    ctx.error([0, paramCheck.check(user, requestParam)]);
  } else {
    const password = user.password.replace(/\s+/g, '+'); // 防止公钥有空格存在
    user.password = key.decrypt(password, 'utf8'); // 解密
    // eslint-disable-next-line quotes
    const sql = "select * from `user` where `name`='" + user.name + "' and `password`='" + user.password + "'";
    const result = await mysql.query(sql);
    if (result[0] && result[0].is_cancel === 0) {
      const tk = ctx.getToken({ name: result[0].name, id: result[0].id }); // token中要携带的信息,自己定义
      ctx.success({
        id: result[0].id,
        token: tk
      });
    } else {
      ctx.error([0, '用户名或密码错误']);
    }
  }
});

/**
 * @swagger
 * /security/publicKey:
 *   get:
 *     description: 获取加密公钥
 *     tags: [用户鉴权模块]
 *     responses:
 *       '200':
 *         description: Ok
 *         schema:
 *           type: 'object'
 *           properties:
 *             code:
 *               type: 'number'
 *               description: 状态码
 *             data:
 *               type: 'string'
 *               description: 加密公钥
 *             message:
 *               type: 'string'
 *               description: 消息提示
 *       '400':
 *         description: 请求参数错误
 *       '404':
 *         description: not found
 */
// 加密公钥获取
router.get('/publicKey', async (ctx, next) => {
  const publicKey = key.exportKey('public'); // 生成公钥
  ctx.success(publicKey);
});

/**
 * @swagger
 * /security/logout:
 *   post:
 *     description: 退出
 *     tags: [用户鉴权模块]
 *     produces:
 *       - application/json
 *     parameters:
 *       -name:
 *        description:
 *        in: query
 *        type: string
 *     responses:
 *       200:
 *         description: 退出成功
 */
router.post('/logout', async (ctx, next) => {
  const decryptTk = ctx.decryptToken(ctx.request.header.token);
  const sql = `DELETE FROM online_token WHERE token = '${decryptTk}'`;
  const result = await mysql.query(sql);
  if (result.affectedRows === 1) {
    ctx.success(true);
  } else {
    ctx.error([0, '退出失败!']);
  }
});

摘取其中三个接口可以发现注释是以@swagger开头得,swagger-jsdoc 会识别@swagger,然后解析下面的注释,解析完给koa2-swagger-ui显示成页面,总的流程就是这样。效果如下:

在这里插入图片描述

具体每个注释的意思我找了三篇写的比较好的文档:

前三个是介绍规范,不过好像中文版的基本都是空的,看第三个英文版的吧!最全;后面一个是在线编写的网站,但是有点不同,不能直接把在线网站里的直接复制进去,这样编译会报错的,要注意下

授权设置

鉴权设置在swagger.js文件的swaggerDefinition对象里添加securityDefinitions属性就好了,文档出处:[OpenAPI-Security Scheme Object]
注意: 打开会发现在右侧导航栏找不到specification-schema-Security Scheme Object,此时需要把页面缩小才能看到(是不是觉得文档做的很垃圾),像下面这样缩放到75%:
在这里插入图片描述
在这里有很多关于安全认证的文档,不过有些按照文档写的不行。例如type文档里说有四种:“apiKey”, “http”, “oauth2”, “openIdConnect”。但是我试了只有两种:apiKey和oauth2可以,不知道是不是我缺了其他的东西,有知道的大佬可以在评论区教学一番,十分感谢!!
配置案例如下:

// 配置,在swagger.js文件下
securityDefinitions: {
	// 这种形式还没整明白
    server_auth: {
      type: 'oauth2',
      description: '密码式',
      tokenUrl: 'http://localhost:4000/image/oauth', // oauth服务接口
      flow: 'password',
      scopes: {
        token: 'modify pets in your account' // 可选项
      }
    },
    // 最简单的token
    token: {
      type: 'apiKey',
      name: 'token',
      in: 'header'
    }
  }

// 使用,在每个接口的swagger注释里,例如:
/**
 * @swagger
 * /security/publicKey:
 *   get:
 *     description: 获取加密公钥
 *     tags: [用户鉴权模块]
 *     responses:
 *       '200':
 *         description: Ok
 *         schema:
 *           type: 'object'
 *           properties:
 *             code:
 *               type: 'number'
 *               description: 状态码
 *             data:
 *               type: 'string'
 *               description: 加密公钥
 *             message:
 *               type: 'string'
 *               description: 消息提示
 *       '400':
 *         description: 请求参数错误
 *       '404':
 *         description: not found
 *     security:
 *       - token: {}
 *       - server_auth:
 *         - token
 */

说明: 在security里虽然有两个鉴权方法:token(apiKey)、server_auth(oauth2)但是后者我还没搞清楚,不知道是不是没有配置对 OAuth 2.0授权服务

OAuth 2.0授权服务

这个服务肯定是错的,太简单了,但是网上关于node这方面的资料太少了,等有时间在尝试吧!有知道的大佬可以在评论区教学一番,十分感谢!!
服务所在地址:OAuth 2.0授权服务地址

router.post('/oauth', (ctx, next) => {
  console.log(ctx.request.body);
  ctx.success({
    access_token: '36034ff7-7eea-4935-a3b7-5787d7a65827',
    token_type: 'bearer',
    refresh_token: '4baea735-3c0d-4dfd-b826-91c6772a0962',
    expires_in: 36931,
    scope: 'token'
  });
});

效果图:
在这里插入图片描述
在这里插入图片描述
oauth2的一点反应都没!!!

注释测试踩过的坑

返回体写法

在The OpenAPI Specification | 开放API规范里Responses 对象是写成这样的:

responses:
  '200':
	description: a pet to be returned
	content:
	  application/json:
	    schema:
	     ...
  default:
	description: Unexpected error
	content:
	  application/json:
	    schema:
	      ...

但是我按着这么写法并没有效果。最后在swagger editor里找到了答案,不需要content和application/json,直接用schema就可以了
在这里插入图片描述
在这里插入图片描述

注释太长占地方

现在简单的接口文档会写了,但是发现一个注释好长好长,后来我使用了// #region和// #endregion的注释把这一个接口文档折叠了起来,代码如下

// #region
/**
 * @swagger
 * /image/{id}:
 *   get:
 *     summary: Returns a list of users.
 *     description: 图片测试
 *     tags: [图片公共模块]
 *     parameters:
 *       - name: id
 *         description: 用户id
 *         in: path
 *         required: true
 *         type: string
 *     responses:
 *       '200':
 *         description: Ok
 *         schema:
 *           type: 'object'
 *           properties:
 *             code:
 *               type: 'number'
 *             data:
 *               type: 'object'
 *               description: 返回数据
 *             message:
 *               type: 'string'
 *               description: 消息提示
 *       '400':
 *         description: 请求参数错误
 *       '404':
 *         description: not found
 */
// #endregion

// 效果
// #region...

这样看起来就会舒服很多,哈哈哈

存在问题

  • oauth2鉴权不知道怎么弄
  • 如何使用$ref

在不断使用中慢慢学习,然后不断的来补充吧,现在学的这些在文本的接口里基本够用了,实在不行再在openAPI规范找一下。
上一篇:node从入门到放弃系列之(7)koa2 token令牌生成、验证、注销
下一篇:node从入门到放弃系列之(9)koa2日志输出及图片上传下载

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Koa 框架时,设置静态目录和使用 koa2-swagger-ui 可能会产生冲突,因为它们都涉及到路由的处理。 当你使用 Koa 的 `koa-static` 中间件设置静态目录时,该中间件会将请求路径匹配到指定的静态文件,并返回给客户端。这意味着如果你的静态目录的路径与 Swagger UI 的路由路径相同,会导致冲突。 为了避免冲突,您可以考虑以下两种解决方案之一: 1. 将 Swagger UI 的路由路径设置为不与静态目录冲突的路径。例如,将 Swagger UI 的路由路径设置为 `/api-docs` 或其他不与现有静态目录路径冲突的路径。 2. 在 Koa 的路由处理中间件之前使用 `koa2-swagger-ui` 中间件。这样可以确保 Swagger UI 的路由优先于其他路由处理中间件执行,避免冲突。 下面是一个示例代码片段,演示了如何在 Koa 中设置静态目录和使用 koa2-swagger-ui: ```javascript const Koa = require('koa'); const serve = require('koa-static'); const koaSwagger = require('koa2-swagger-ui'); const app = new Koa(); // 设置静态目录 app.use(serve('public')); // 设置 Swagger UI app.use(koaSwagger({ routePrefix: '/api-docs', // 设置 Swagger UI 的路由路径 swaggerOptions: { url: '/swagger.json', // 设置 Swagger JSON 文件的路径 }, })); // 添加其他路由处理中间件 // ... app.listen(3000, () => { console.log('Server started on port 3000'); }); ``` 在上述示例中,静态目录设置为 `public`,Swagger UI 的路由路径设置为 `/api-docs`。这样就可以避免静态目录和 Swagger UI 的冲突。 请根据您的具体需求和项目结构进行适当的调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值