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一起用 有待考察