koa-swagger-decorator 源码简单阐述(草稿)

核心文件
wrapper.ts

  1. 用于依据 decorator 函数执行后得到的数据进行 router 的自动化构建,同时根据 middlewares 函数的结果在 router 构建时添加相对应的中间件。
  2. 基于 swaggerObject 构建 swagger 文档

swaggerObject.ts
swagger 文档可以使用 json 描述, swaggerObject 暴露出一个 SwaggerObject 的实例,提供添加对应的 swagger 字段的方法供 decorator 使用,并且暴露出 data 字段表示整个 swagger 对象,用于构建 swagger json 文档

decorators.ts
定义使用的 decorator,如 @request,@summary 等。由于 swagger 文档的构建中,对个字段会有相似的结构,如 summary 与 description 的格式相同,所以为了使得 decorator 函数更加简洁,使用curry化的方式优化代码结构。如下

const _desc = (type: string, text: string | any[]) => (target: any, name: string, descriptor: PropertyDescriptor) => {
  descriptor.value[type] = text;
  swaggerObject.add(target, name, { [type]: text });
  return descriptor;
};
const desc = _.curry(_desc);
const description = desc('description');
const summary = desc('summary');
const tags = desc('tags');

这些 decorator 会需要处理两件事,一是对于 swaggerObject 要添加相关字段内容,二是对于 router 构建要添加相关字段内容,如 @request 需要添加 path,method 两个字段到绑定的方法中,使得 wapper.js 中可以根据这些信息构建 router

validate/index.ts
validate/check.ts
这两个文件用于对 decorator 定义的参数进行校验。关键难点在于对于 swagger 中 array 和 object 嵌套结构的校验,利用递归的方式实现。参考代码如下,在 cObject 中调用 check 校验嵌套数据。

const check = (input: any, expect: Expect) => {
  const cond = _.cond([
    [_.equals('string'), () => cString(input, expect)],
    [_.equals('boolean'), () => cBool(input, expect)],
    [_.equals('number'), () => cNum(input, expect)],
    [_.equals('object'), () => cObject(input, expect)],
    [_.equals('array'), () => cArray(input, expect)],
    [_.T, () => ({ is: true, val: input })] // 其他类型不做校验,直接返回原数据
  ]);

  return cond(expect.type);
};


// /**
//  * 对 Object 做检验, 支持嵌套数据
// {
//   aaaa: 'hh',
//   bbbb: 'qq',
// }
// { // expect:
//   type: 'object',
//   properties: {
//     aaaa: { type: 'string', example: 'http://www.baidu.com', required: true },
//     bbbb: { type: 'string', example: 'Bob' }
//     c: { type: 'object', properties: {ii: {type: 'string'}, jj: {type: 'number'}} }

//   }
// }
//  */
const cObject = (input: any, expect: Expect = {}) => {
  if (!cRequired(input, expect).is) return { is: false };

  const res = { is: true, val: input };
  if (!is.object(input)) return { is: false };
  if (!expect.properties) return res;

  for (const key of Object.keys(expect.properties)) {
    // ignore empty key if not required
    if (!expect.properties[key].required && input[key] === undefined) {
      continue; // eslint-disable-line
    }
    const { is, val } = check(input[key], expect.properties[key]);
    if (!is) {
      console.log('error object properties:', key); // TODO need to update error debug info
      res.is = false;
      break;
    }
    input[key] = is ? val : input[key];
  }
  return res;
};

你可能感兴趣的:(koa-swagger-decorator 源码简单阐述(草稿))