egg中引入swagger

swagger简介

什么是swagger?

Swagger 是一个开放源代码的软件框架,旨在帮助开发人员设计、构建、记录和使用 RESTful API。Swagger 提供了一套工具和规范,使得 API 开发和文档生成变得更加高效和标准化。

我们在平时开发后端接口的时候非常需要一个接口文档,而且具有可测试性,这样我们既可以方便前后端的一个接口联调,也可以让后端有一个可测试性的工具

官网地址:https://swagger.io/

egg中使用swagger

关于在egg框架中如何使用swagger呢,在github上有很多相关的插件,这里使用的是egg-swagger-doc插件

$ npm i egg-swagger-doc --save

基本配置

然后在egg的配置文件config/plugins.js里面加入

exports.swaggerdoc = {
  enable: true,
  package: 'egg-swagger-doc',
};

在config/config.default.js可以配置的内容

// {app_root}/config/config.default.js
exports.swaggerdoc = {
  dirScanner: './app/controller',
  apiInfo: {
    title: 'egg-swagger',
    description: 'swagger-ui for egg',
    version: '1.0.0',
  },
  schemes: ['http', 'https'],
  consumes: ['application/json'],
  produces: ['application/json'],
  securityDefinitions: {
    // apikey: {
    //   type: 'apiKey',
    //   name: 'clientkey',
    //   in: 'header',
    // },
    // oauth2: {
    //   type: 'oauth2',
    //   tokenUrl: 'http://petstore.swagger.io/oauth/dialog',
    //   flow: 'password',
    //   scopes: {
    //     'write:access_token': 'write access_token',
    //     'read:access_token': 'read access_token',
    //   },
    // },
  },
  enableSecurity: false,
  // enableValidate: true,
  routerMap: false,
  enable: true,
};

具体使用

这里的话在controller我们需要具体的去使用,我们在controller文件里面的对应的函数名上面加入它的一些自定义的注解,就可以实现swagger文档的自动生成,这里的话大概的使用方式如下:

/controller/auth/role.js

const baseController = require('../../core/baseController');

/**
 * @description 角色
 * @controller 角色管理 角色管理 权限管理
 * @author gerry
 * @date : 2023-09-25 16:59:04
 */
class roleController extends baseController {
  /**
   * @summary 获取角色列表
   * @description 获取角色列表信息
   * @author gerry
   * @request header string Authorization Bearer \u0020{{token}} description:token权限校验
   * @response body roleListResponse 角色列表
   * @router get /auth/role/list
   * @date : 2023-09-25 16:59:04
   */
  //列表
  async list() {
    const { ctx, service } = this;

    ctx.body = await service.auth.role.findRoleList();
  }

  /**
   * @summary 获取角色详情
   * @description 获取角色详情信息
   * @author gerry
   * @request header string Authorization Bearer \u0020{{token}} description:token权限校验
   * @request path interger *id
   * @response body roleDetailResponse 角色详情
   * @router get /auth/role/detail/{id}
   * @date : 2023-09-25 16:59:04
   */
  //详情
  async detail() {
    const { ctx, service } = this;

    const { id } = ctx.params;

    ctx.body = await service.auth.role.findRoleDetail(id);
  }

  /**
   * @summary 获取角色分页
   * @description 获取角色分页信息
   * @author gerry
   * @request header string Authorization Bearer \u0020{{token}} description:token权限校验
   * @request query interger pageNum 页码 默认1 default:1
   * @request query interger pageSize 单页数量 默认10 default:10
   * @response body rolePageResponse 角色分页
   * @router get /auth/role/page
   * @date : 2023-09-25 16:59:04
   */
  //分页
  async page() {
    const { ctx, service } = this;
    const opts = ctx.request.query;

    ctx.body = await service.auth.role.findRolePage(opts);
  }

  /**
   * @summary 添加角色
   * @description 添加角色信息
   * @author gerry
   * @request header string Authorization Bearer \u0020{{token}} description:token权限校验
   * @request body createRoleRequest *body
   * @response body baseResponse *body
   * @router post /auth/role/add
   * @date : 2023-09-25 16:59:04
   */
  //创建
  async create() {
    const { ctx, service } = this;
    await service.auth.role.addRole(ctx.request.body);
  }

  /**
   * @summary 编辑角色
   * @description 编辑角色信息
   * @author gerry
   * @request header string Authorization Bearer \u0020{{token}} description:token权限校验
   * @request body updateRoleRequest *body
   * @response body baseResponse *body
   * @router post /auth/role/edit
   * @date : 2023-09-25 16:59:04
   */
  //编辑
  async update() {
    const { ctx, service } = this;
    await service.auth.role.editRole(ctx.request.body);
  }

  /**
   * @summary 删除角色
   * @description 删除角色信息
   * @author gerry
   * @request header string Authorization Bearer \u0020{{token}} description:token权限校验
   * @request query integer ids*
   * @response body baseResponse *body
   * @router post /auth/role/delete
   * @date : 2023-09-25 16:59:04
   */
  //删除
  async destroy() {
    const { ctx, service } = this;

    ctx.validate({ ids: 'string' }, ctx.request.query);

    await service.auth.role.deleteRole(ctx.request.query.ids);
  }

  /**
   * @summary 导出角色信息
   * @description 导出角色信息
   * @author gerry
   * @request header string Authorization Bearer \u0020{{token}} description:token权限校验
   * @router post /auth/role/export
   * @response body baseResponse *body
   * @date : @date : 2023-09-25 16:59:04
   */
  async export() {
    await this.exportExcel('auth.role', 'exportRole', '角色信息');
  }
}
module.exports = roleController;

重点是下面这一段,controller里面的author和date不需要管,是我自己加进去的,controller外面只有@controller是有用的,如果加上这个它会扫描这个文件的所有注释块

/**
 * @description 角色
 * @controller 角色管理 角色管理 权限管理
 * @author gerry
 * @date : 2023-09-25 16:59:04
 */
class roleController extends baseController {

/**
   * @summary 获取角色列表
   * @description 获取角色列表信息
   * @author gerry
   * @request header string Authorization Bearer \u0020{{token}} description:token权限校验
   * @response body roleListResponse 角色列表
   * @router get /auth/role/list
   * @date : 2023-09-25 16:59:04
   */
  async list() {
  		...
  }
}
  • @controller

  • @summary 表示接口小标题

  • @description 表示接口具体描述

  • @request 表示请求相关,格式@Request {Position} {Type} {Name} {Description}

a.position.参数的位置,该值可以是body/path/query/header/formData.
b.Type.参数类型,body之外位置目前只支持基础类型,integer/string/boolean/number,及基础类型构成的数组,body中则支持contract中定义的类型。如果position是formData还将支持 file 类型
c.Name.参数名称.如果参数名称以*开头则表示必要,否则非必要。
d.Description.参数描述
c.如果你想给query或者path的参数设置example,你可以在Description前添加以'eg:'开头的参数,实例如下
@Request query string contactId eg:200032234567 顾问ID
  • response,格式:@Response {HttpStatus} {Type} {Description}
a.HttpStatus.Http状态码。
b.Type.同Request中body位置的参数类型。
d.Description.响应描述。
  • router,格式:@Router {Mothod} {Path}
a.Mothod,请求的方法(post/get/put/delete等),不区分大小写。
b.Path,请求的路由。

他这里的response的body设置的roleListResponse需要在另一个文件里面单独定义这个响应值的类型

我们需要在项目的根目录/app下创建contract文件夹,contract文件夹里面再创建request和response文件夹,request和response里面的文件夹的文件名任意,但是里面的内容如下:

request的

'use strict';

module.exports = {
  createRoleRequest: {
    name: { type: 'string', required: true, description: '角色名称' },
    code: { type: 'string', required: true, description: '角色代码' },
    role_desc: { type: 'string', required: true, description: '角色描述' },
    menuIdList: { type: 'array', itemType: 'string', description: '菜单id列表' }
  },
  updateRoleRequest: {
    name: { type: 'string', required: true, description: '角色名称' },
    code: { type: 'string', required: true, description: '角色代码' },
    role_desc: { type: 'string', required: true, description: '角色描述' },
    id: { type: 'string', require: true, description: '角色id' },
    menuIdList: { type: 'array', itemType: 'string', description: '菜单id列表' }
  }
};

response的

'use strict';
const { baseResponse } = require('./base');
module.exports = {
  roleListResponse: {
    ...baseResponse,
    data: {
      type: 'array',
      description: '列表数据',
      itemType: 'roleListItem'
    }
  },
  rolePageResponse: {
    ...baseResponse,
    data: {
      type: 'array',
      description: '分页数据',
      itemType: 'rolePageItem'
    }
  },

  roleDetailResponse: {
    ...baseResponse,
    data: {
      type: 'object',
      description: '分页数据',
      properties: {
        id: { type: 'string', description: 'id 唯一键' },
        name: { type: 'string', description: '角色名称' },
        code: { type: 'string', description: '角色代码' },
        role_desc: { type: 'string', description: '角色描述' },
        create_time: {
          type: 'string',
          format: 'date-time',
          description: '创建时间'
        },
        update_time: {
          type: 'string',
          format: 'date-time',
          description: '更新时间'
        }
      }
    }
  },

  roleListItem: {
    id: { type: 'string', description: 'id 唯一键' },
    name: { type: 'string', description: '角色名称' },
    code: { type: 'string', description: '角色代码' },
    role_desc: { type: 'string', description: '角色描述' },
    create_time: {
      type: 'string',
      format: 'date-time',
      description: '创建时间'
    },
    update_time: {
      type: 'string',
      format: 'date-time',
      description: '更新时间'
    }
  },

  rolePageItem: {
    id: { type: 'string', description: 'id 唯一键' },
    name: { type: 'string', description: '角色名称' },
    code: { type: 'string', description: '角色代码' },
    role_desc: { type: 'string', description: '角色描述' },
    create_time: {
      type: 'string',
      format: 'date-time',
      description: '创建时间'
    },
    update_time: {
      type: 'string',
      format: 'date-time',
      description: '更新时间'
    }
  }
};

这里其实就是用来配置接口需要传递的哪些参数?或者是接口响应回来有哪些参数,不配置这些的话,egg-swagger-doc会报错,找不到相关地方的这个配置

更加详细的配置可以查看它的官方文档:https://github.com/Yanshijie-EL/egg-swagger-doc

配置完成以后,我这里就可以通过 本地ip+项目端口号/swagger-ui.html进行访问

在这里插入图片描述

在这里插入图片描述

代码片段

我们每次要使用的话太麻烦了,每次都得手动去敲@xxx,很浪费时间,所以这里我们可以使用代码片段的方式,当然这个作者也有给我们提供,具体的使用请查看:https://github.com/taccisum/swagger-doc-snippets

扩展egg-swagger-doc插件

在使用的途中我还用的不太舒服,毕竟在这边使用还是有些不太爽,我想把他引入到apifox里面,apifox它是支持把swagger的json数据的url直接导入到apifox里面的,但是egg-swagger-doc插件里面不支持多层目录,不能进行拆分,我后面仔细剖析了它的源码,进行了一些修改

我把node_modules里面的egg-swagger-doc文件夹单独拖出来,然后项目根目录创建lib,创建plugin,把文件夹复制到plugin下面

然后更改了下配置文件的config/plugins.js

exports.swaggerdoc = {
  enable: true,
  package: 'egg-swagger-doc',
  path: path.join(__dirname, '../lib/plugin/egg-swagger-doc')
};

这样的话,就可以使用修改后的源码的egg-swagger-doc插件了

根据源码分析,我加了一段代码,让生成的tags多一个组的概念

在这里插入图片描述

这样生成的/swagger-doc就会存在组的概念,导入apifox就是我想要的效果

这个是没加组别的导入

在这里插入图片描述

这个是加了组别的导入,约等于我在@controller里面的配置有多加了第三项,多一项组别,后面显示会更加灵活

在这里插入图片描述

apifox

APIFox 是一个集成的 API 管理工具,旨在简化和优化 API 的设计、开发、测试和文档管理过程。它集成了 API 设计、调试、测试、Mock 服务和文档生成等多种功能,为开发者提供一站式的解决方案。

导入apifox

这里其实特别简单,只需要把本地ip + 端口号 /swagger-doc的路径进行导入,就会生成好对应的swagger,可以随意的测试,非常的方便

在这里插入图片描述

结语

其实这里重点就是了解swagger,以及如何在egg中引入swagger,swagger是一个通用的接口文档生成的工具,不管是什么后端语言都可以进行使用的,所以关于swagger重点还是要了解它官网的一些配置,今天的分享就到这里,下期会分享这个插件结合代码生成器完成自动的crud

  • 18
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值