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