duuliy

nest总结

2019-5-1

  从express到koa再到现在的nest+Graphgl, node的框架越来越棒了, 话说有没感觉它的写法和最近接触的堡垒机的ng7代码很像,哈哈,学了springboot之后,又会觉得两者思路上的相似。
一查资料果然印证猜想

1.应用程序

创建一个http服务

const server = express();
async function bootstrap() {
}
bootstrap();
http.createServer(server).listen(3000);
2.导入module
@Module({
  imports: [ //导入模块的列表
    userGraphqlModule,
    GraphQLModule.forRoot({   //http://localhost:3000/graphql
      path: '/graphql',
      typePaths: ['./**/*.graphql'],
      definitions: {
        path: join(process.cwd(), 'src/classGraphql/graphql.schema.ts'),  //自动生成class
        outputAs: 'class'
      },
      installSubscriptionHandlers: true
    }),
    UserModule,
    CacheModule.register()  //只有使用 @Get() 方式声明的节点会被缓存。
    // ConfigModule
  ],
  controllers: [AppController, CatsController, CarController, ErrorController],
  providers: [
    WsGateway,
    AppService,
    CatsService,
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter, //全局
    },
    {
      provide: APP_INTERCEPTOR,
      useClass:TimeoutInterceptor
    }
    // {
    //   provide: APP_INTERCEPTOR,
    //   useClass: CacheInterceptor,  //全局缓存 不能和GraphQL  一起用
    // }
  ],
  exports: [], // 由本模块提供并应在其他模块中可用的提供者的子集。
})
// export class AppModule {}
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
3.编写Controller
@Controller()
export class AppController {
  constructor(private readonly appService: AppService<any>) {}

  @Get()
  // @UsePipes(new JoiValidationPipe(createCatSchema))
  @UseInterceptors(LoggingInterceptor)
  getHello(): string {
    return this.appService.getHello();
  }
4.查询serve
@Injectable()
export class UserService {
  constructor(
    @Inject('USER_REPOSITORY')
    private readonly usersRepository: Repository<User>
  ) {}

  async findAll(): Promise<User[]> {
    return await this.usersRepository.find();
  }

还可以用Graphql

@Injectable()
export class GraphqlService {
  private readonly users: User[] = [{ id: 1, userName: 'duuliy1',sex:1,height:1,weight:1 }];

  create(user: User): User {
    this.users.push(user);
    return user;
  }

   async findAll(): Promise<User[]> {
    const body=await axios.get(`${TARGET_SERVER}mysql`).then(resp => {
        // console.log('statusCode:', resp.status); // 返回请求的状态码
        // console.log('body:', resp.data); // 返回回来的数据
        //这里可以调用多个接口聚合数据
        return resp.data
    })
    return body
  }
5.bean
@Entity() //代表是bean的实体
export class User {
  @ApiProperty()
  @PrimaryGeneratedColumn() //代表主键
  readonly id?: number;

  @ApiProperty()
  @Column({ 
    type: 'char',
    length: 100
  })
  readonly userName: string;

  @ApiProperty()
  @Exclude()  //返回值排除此选项
  @Column({ 
    type: 'char',
    length: 100
  })
  readonly password: string;
6. 连接池
export const databaseProviders = [
  {
    provide: 'DATABASE_CONNECTION',
    useFactory: async () =>
      await createConnection({
        type: 'mysql',
        host: 'localhost',
        port: 3306,
        username: 'root',
        password: 'root',
        database: '',
        entities: [__dirname + '/../**/*.entity{.ts,.js}'],
        synchronize: true, //同步
      }),
  },
];
6.设置pipe 和filter

面向切面


@Injectable()
export class ValidationPipe implements PipeTransform<any> {
  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }
    const object = plainToClass(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      throw new BadRequestException('Validation failed');
    }
    return value;
  }

  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}
@Catch(HttpException) //捕获http异常类型
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
        message:exception.message.error
      });
  }
}
7.还可以设置中间件,ts支持棒棒的

注意:
全局缓存CacheInterceptor 不能和GraphQL 一起用(用就报错),因为 GraphQL 本来就有缓存(如:dataloader),是否能和redis一起用 有待考察