1.1.4 • Published 3 years ago

egg-pandora v1.1.4

Weekly downloads
2
License
MIT
Repository
github
Last release
3 years ago

egg-pandora

NPM version build status Test coverage David deps Known Vulnerabilities npm download

Pandora & EGG JS

  • npm i egg-pandora --save

Pandora 套件说明

  • 添加 Dto/Dao AOP 切面
  • 添加 Swagger JSDOC 注释生成文档
  • 添加 router 路由修饰器
  • 后续迭代更多功能
npm i egg-pandora --save

Usage

// {app_root}/config/plugin.ts
import { EggPlugin } from 'egg';

const plugin: EggPlugin = {
    // static: true,
    // nunjucks: {
    //   enable: true,
    //   package: 'egg-view-nunjucks',
    // },
    pandora: {
        enable: true,
        package: 'egg-pandora',
    }
};

export default plugin;

Configuration

// {app_root}/config/config.default.ts
import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg';

export default (appInfo: EggAppInfo) => {
    const config = {} as PowerPartial<EggAppConfig>;

    // override config from framework / plugin
    // use for cookie sign key, should change to your own and keep security
    config.keys = appInfo.name + '_1605494805703_9866';

    // add your egg config in here
    config.middleware = [];

    // add your special config in here
    const bizConfig = {
        sourceUrl: `https://github.com/eggjs/examples/tree/master/${appInfo.name}`,
    };

    const swagger = {
        dirScanner: './app/controller',
        DOCJSONPath: '/swagger.json',
        DOCPath: '/swagger.io',
        apiInfo: {
            title: '测试用例',
            description: 'API Swagger 用例',
            version: '1.0.0',
        },
        schemes: ['http', 'https'],
        consumes: ['application/json'],
        produces: ['application/json'],
        securityDefinitions: {
            apikey: {
                type: 'apiKey',
                name: 'accesstoken',
                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: true,
        enable: true,
    };

    // the return config will combines to EggAppConfig
    return {
        ...config,
        ...bizConfig,
        pandora: {
            router: {
                autoloader: true,
            },
            swagger,
            // typeorm: false,
        },
        typeorm: {
            type: 'mysql',
            host: '127.0.0.1',
            port: 33066,
            username: 'root',
            password: 'jzzs2020',
            database: 'jzzs',
            synchronize: true,
            logging: false,
            entities: ['app/entity/**/*.ts'],
            migrations: ['app/migration/**/*.ts'],
            subscribers: ['app/subscriber/**/*.ts'],
            cli: {
                entitiesDir: 'app/entity',
                migrationsDir: 'app/migration',
                subscribersDir: 'app/subscriber',
            },
        },
        multipart: {
            mode: 'file',
            tmpdir: join(tmpdir(), 'pandora', appInfo.name),
            cleanSchedule: {
                // run tmpdir clean job on every day 04:30 am
                // cron style see https://github.com/eggjs/egg-schedule#cron-style-scheduling
                cron: '0 30 4 * * *',
            },
        },
        security: {
            xframe: { enable: false },
            csrf: { enable: false },
        },
    };
};

基本使用

  • 启动 Pandora 套件
  • app/router.ts
import { Application } from 'egg';
import { router } from 'egg-pandora';

export default (app: Application) => router(app);
  • swagger 通过 注释生成 可 配合 AOP 切面使用
  • AOP 切面 自动把 validator-class 转成 jsonschema
  • 这里注意一下 swagger 中使用 AOP 切面直接备注 切面名即可
  • app/controller/home.ts
import { Controller } from 'egg';
import { RequestMapping, RequestMethod, RestController, Before, ABefore } from 'egg-pandora';
import { HomeDataDto } from '../dto/home';

/**
 * @controller home
 */
@Before((ctx, next) => {
    ctx.body = { name: 'test' };
    return next();
})
@RestController
// @RestController(['/home', '/v1/home'])
export default class extends Controller {

    /**
     * @summary 测试
     * @router POST /home/test false
     * @router POST /v1/home/test
     * @request query string test 测试
     * @request body string name 名字
     * @response default HomeDataDto
     * @response 200 Test1
     * @apikey
     */
    @ABefore((ctx, next) => {
        ctx.body = { name: 'test1' };
        return next();
    })
    @RequestMapping({ path: 'test', methods: [RequestMethod.POST] })
    public async test() {
        console.log('query', this.ctx.request.query);
        console.log('body', this.ctx.request.body);
        this.ctx.body = {};
    }

    /**
     * @summary 创建资源
     * @router POST /home/index/{id}/{uid}
     * @request path string id ID
     * @request path string uid UID
     * @request query string test 测试
     * @request query string test1 测试1
     * @request formdata file file 文件 false
     * @request formdata file file1 文件1 false
     * @request body string name 名字
     * @request body string age 年龄
     * @consumes multipart/form-data
     * @apikey
     */
    @RequestMapping({ path: 'index/:id/:uid', methods: [RequestMethod.POST] })
    public async index() {
        console.log('path', this.ctx.params);
        console.log('query', this.ctx.request.query);
        console.log('header', this.ctx.request.headers);
        console.log('body', this.ctx.request.body);
        console.log('file', this.ctx.request.files);
        const { ctx } = this;
        console.log(await ctx.vaildAOP(HomeDataDto, {}));

        // ctx.body = await ctx.service.test.sayHi('egg');
        ctx.body = await ctx.service.test.test();
    }
}
  • entity 数据模型
  • 这里注意一下 sql 和 QueryBuilder 分在此层 单独抽离略嫌麻烦
  • 习惯了非常好用哦 非常推荐
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
import { PColumn, IsDate, IsEmail, IsInt, Length, TypeOrm } from 'egg-pandora';

export enum UserType {
    WX = 'WX', QQ = 'QQ', DEFAULT = 'DEFAULT',
}

// PColumn 可自动生成 JSONschema 注释
@Entity()
export class User extends TypeOrm<User> {

    @IsInt()
    @PColumn(PrimaryGeneratedColumn, { comment: '用户 ID' })
    public id!: number;

    @IsEmail()
    @PColumn(Column, { type: 'varchar', length: 50, nullable: false, comment: '邮箱' })
    public email!: string;

    @Column({ type: 'varchar', length: 100, nullable: true, comment: '密码' })
    public password!: string;

    @Length(1, 10)
    @PColumn(Column, {
        length: 10, nullable: false, default: UserType.DEFAULT,
        type: 'char', comment: '平台 QQ WX 等 默认 defaut',
    })
    public type!: string;

    @IsInt()
    @PColumn(Column, { type: 'int', nullable: false, default: 0, comment: '是否激活' })
    public isActived!: number;

    @IsDate()
    @PColumn(CreateDateColumn, { type: 'timestamp', nullable: false, comment: '创建时间' })
    public createdAt!: Date;

    @IsDate()
    @PColumn(UpdateDateColumn, { type: 'timestamp', nullable: false, comment: '修改时间', update: true })
    public updatedAt!: Date;

    public async queryAll() {
        // 可以使用 query builder sql 等 ...
        return this.findAndCount();
    }
}
import { IsNotEmpty, ValidateNested, Dto } from 'egg-pandora';
import { User } from '@entity/user';

export class UserResponseDto extends Dto {

    @IsString()
    public error!: string;
    @IsInt()
    public errno!: number;

    @ValidateNested()
    @IsNotEmpty()
    public data: User;
}
  • logic 层 做数据验证 这里对用 controller 的 文件名 和目录结构
  • logic 移植于 thinkjs 可参考 thinkjs logic
  • context 添加 this.ctx.param(name?:string) 和 this.ctx.post(name?: string) this.ctx.file(name?:string)
  • 用法与 thinkjs 一致
  • app/logic/user.ts
import { Logic, PandoraLogicRules, RequestMethod } from 'egg-pandora';
import { Context } from 'egg';

export default class extends Logic {

    constructor(ctx: Context) {
        super(ctx);
        console.log('logic');
    }

    public async index() {
        const rules: PandoraLogicRules = {
            name: {
                string: true,
                required: true,
                method: [RequestMethod.POST],
            }
        };
        const valid = this.validate(rules);
        console.log(111, valid);
        this.ctx.body = `error`;
        return false;
    }
}
  • 添加 JWT 验证
  • config/plugin.ts
import { EggPlugin } from 'egg';

const plugin: EggPlugin = {
    // ...
    jwt: {
        enable: true,
        package: 'egg-jwt'
    },
};

export default plugin;
  • 添加 JWT 验证
  • config/config.env.ts
import { EggAppInfo } from 'egg';

export default (appInfo: EggAppInfo) => {
    // the return config will combines to EggAppConfig
    return {
        // ...
        jwt: {
            secret: '123456'
        },
    };
};