Koa+koa-swagger-decorator实战篇:打造高效优雅的API文档

前言

好记性不如烂笔头,记录一下koa接入swagger踩得坑

So here's the question(那么问题来了),我们为什么要写接口文档呢?

为什么要写接口文档?

  1. 提供清晰的接口定义:接口文档可以详细描述接口的功能、参数、返回值等,使开发人员清楚了解如何正确调用接口。
  2. 促进团队合作:接口文档可以作为开发人员、产品经理、测试人员等不同角色之间的沟通工具,确保大家对接口的理解一致,减少沟通成本。
  3. 确保开发质量:接口文档可以作为开发人员编写单元测试、集成测试和验收测试的依据,确保开发过程中的质量控制。
  4. 方便接口调试和问题排查:接口文档可以帮助前后端开发人员在调试接口时快速定位问题,加快问题排查和解决的速度。
  5. 支持接口升级和扩展:接口文档可以指导开发人员进行接口的升级和扩展,同时也可以帮助其他开发人员快速了解新接口的使用方式。

所以写好接口文档是一个成熟的程序员必备的技能

安装

js 复制代码
pnpm i koa-swagger-decorator@next //notice: 一定要加next,我们要使用最新的版本,2版本,如果不加的话,那么可能就会使用1版本了

有人这里可能要问了,为什么不用koa2-swagger-ui swagger-jsdoc呢,用过的小伙伴应该都知道,那文档真是越写越多,啥都要写,本来我使用swagger来减轻工作量的,结果工作量越来越大,这不和我们的初衷相反么。而有的小伙伴说koa-swagger-decorator的入侵性很强,不适合二次开发?我对此表示疑问。我觉得koa-swagger-decorator写起来方便,也方便修改。我觉得还好呀。

文档地址GitHub - Cody2333/koa-swagger-decorator: using decorator to automatically generate swagger doc for koa-router

大家如果有什么使用问题,也可以提issue,writer也会很快回答的right now

一个完整的配置过程

支持装饰器模式

因为要支持装饰器模式,所以要安装

js 复制代码
pnpm install babel-plugin-transform-decorators-legacy

然后配置babelrc

js 复制代码
{
  "presets": [["env", { "targets": { "node": "current" } }]],
  "plugins": ["transform-decorators-legacy"]
}

typescript配置

这是必须配置的

js 复制代码
// tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "esModuleInterop": true,
  }
}

新建src/routes/index.ts文件

因为koa-swagger-decorator包括routes了,所以所有routes啥的都可以在这里配置,并且不需要引入 koa-router

js 复制代码
import { SwaggerRouter } from 'koa-swagger-decorator';
import UserController from '../controller/user';
import { registerExtraComponents } from '../common/swagger-extra';

const router = new SwaggerRouter({
  spec: {
    info: {
      title: 'koa模版',
      version: 'v1.0',
    },
  },
  swaggerHtmlEndpoint: '/swagger-html',
  swaggerJsonEndpoint: '/swagger-json',
});

router.prefix('/api');

registerExtraComponents(router.registry);

// apply swagger docs routes
// 只开发环境运行
if (process.env.NODE_ENV === 'development') {
  router.swagger();
}
// register user defined routes implementation
router.applyRoute(UserController);
// .applyRoute(DemoController); // chained for more then one controller imports

export default router;

notice: 所有的Controller都要applyRoute,否则会不起作用

配置授权

这样我们就可以配合jwt使用了

ts 复制代码
export const AUTH_KEY = 'authorization';

export function registerExtraComponents(registry: any) {
  registry.registerComponent('securitySchemes', 'authorization', {
    type: 'apiKey',
    name: 'authorization',
    in: 'header',
  });

  registry.registerComponent('schemas', 'ExtraSchemasA', {
    type: 'object',
    properties: {
      id: {
        type: 'string',
      },
    },
  });
}

notice: input内容的时候一定要加Bearer,不加的话不会生效,谨记

使用

ts 复制代码
import { routeConfig, z, body, ParsedArgs } from 'koa-swagger-decorator';
// 需要授权的接口要使用
import { AUTH_KEY } from '../../common/swagger-extra';
class UserController {
  @routeConfig({
    path: '/login',
    method: 'post',
    summary: 'user login',
    tags: ['USER'],
  })
  @body(CreateUserReq)
  async login(ctx: Models.Ctx, args: ParsedArgs<LoginType>) {
    const { username, password } = args.body as LoginType;
    const user = await ctx.model.User.findOne({
      where: { user_name: username },
    });
    if (!user) {
      ctx.fail('该用户不存在');
      return;
    }
    if (password !== user.password) {
      ctx.fail('密码错误');
      return;
    }
    const token = jwt.sign(
      {
        username,
      },
      Config.JWT.secret,
      { expiresIn: 60 * 60 }
    );
    ctx.success({ token }, '登录成功');
  }

  @routeConfig({
    // define your API route info using @routeConfig decorator
    method: 'get',
    path: '/users',
    summary: 'get users',
    tags: ['USER'],
    security: [{ [AUTH_KEY]: [] }], // notice: 需要授权的接口要加上security,不需要授权的就不需要写了
  })
  async getUsers(ctx: Models.Ctx) {
    const users = await ctx.model.User.findAll({
      attributes: {
        exclude: ['password'],
      },
    });
    ctx.success(users);
  }

  @routeConfig({
    method: 'post',
    path: '/register',
    summary: 'create user',
    tags: ['USER'],
  })
  @body(CreateUserReq)
  async register(ctx: Models.Ctx, args: ParsedArgs<RegisterType>) {
    const { password, username } = args.body as RegisterType;
    // TODO:增加判断是否有重复用户
    const user = await ctx.model.User.findOne({
      where: { user_name: username },
    });
    if (user) {
      ctx.fail('用户重复');
      return;
    }
    // TODO:密码检测
    // 注册
    await ctx.model.User.create({ password, user_name: username });
    ctx.success('', '注册成功');
  }
}

此时访问/api/swagger-html 就可以了

配置了security的接口会有一把锁子的标志,需要设置Authorization才行

总结

大家知道写一个接口文档很麻烦的,是一个重复的工作,有人说,大家接到需求的时候就要写呀,要不怎么前后端分离开发,可是随着接口体系的越来越庞大,所有的接口就需要一个总的文档,并且后续如果需要改接口的话,前端也可以很快进行修改,方便维护。

希望大家能从文章中学到东西,有什么使用问题都可以随时在评论区留言

参考

相关推荐
Android系统攻城狮31 分钟前
鸿蒙系统Openharmony5.1.0系统之解决编译时:Node.js版本不匹配问题(二)
node.js·鸿蒙系统·openharmony·编译问题·5.1
神奇小汤圆31 分钟前
浅析二叉树、B树、B+树和MySQL索引底层原理
后端
文艺理科生41 分钟前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling41 分钟前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
南极企鹅43 分钟前
springBoot项目有几个端口
java·spring boot·后端
Luke君607971 小时前
Spring Flux方法总结
后端
define95271 小时前
高版本 MySQL 驱动的 DNS 陷阱
后端
忧郁的Mr.Li1 小时前
SpringBoot中实现多数据源配置
java·spring boot·后端
清山博客1 小时前
OpenCV 人脸识别和比对工具
前端·webpack·node.js
暮色妖娆丶2 小时前
SpringBoot 启动流程源码分析 ~ 它其实不复杂
spring boot·后端·spring