上一章中,通过seeder实现了数据的自动生成以及crud操作。但是在使用findAll时,是将所有的数据都返回。一般来说,我们会通过分页的方式控制一次返回数据的数量。
根据官网的API手册,可以看到,FindAll可以传入FindOption,其中包括limit,offset,orderBy等参数。
在NestJS中定义查询参数,关键词为:@Query()
1.定义查询参数的Dto
在dto文件夹下创建filter-todo.dto.ts
export class FilterTodoDto{
page:number;
limit:number;
orderBy:'asc'|'desc'
}
2.修改controller和service中的findAll函数
@Get()
findAll(@Query() filterTodoDto: FilterTodoDto) {
return this.todosService.findAll(filterTodoDto);
}
async findAll(filterTodoDto: FilterTodoDto) {
const { page, limit, orderBy } = filterTodoDto;
const offset = (page - 1) * limit;
return await this.todoRepository.findAll({
limit,
offset,
orderBy: { id: orderBy },
});
}
3.增加Dto校验
使用class-validator和class-transform
首先安装pnpm add class-validator class-transform。然后在main.ts中添加管道
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,//如果前端传来的JSON数据中包括DTO中没有定义的字段,将多余字段丢掉
forbidNonWhitelisted: true,//检测到多余字段后报错
transform: true,//自动将传过来的数据实例化为DTO类
transformOptions: {
enableImplicitConversion: true,
},
}),
);
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
通过使用transform: true。我们就可以将原本的controller中的
@Get(':id')
findOne(@Param('id') id: string) {
return this.todosService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateTodoDto: UpdateTodoDto) {
return this.todosService.update(+id, updateTodoDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.todosService.remove(+id);
}
改成,因为程序会自动帮我们在DTO中定义的id:number将JSON数据中的字符串类型转换为string类型。!!!注意,这里transfrom只会将我们这里简单的路径参数做类型转换,但是查询参数是无法类型转换的。(因此还需要加上transformOptions: { enableImplicitConversion: true, },)
@Get(':id')
findOne(@Param('id') id: number) {
return this.todosService.findOne(id);
}
@Patch(':id')
update(@Param('id') id: number, @Body() updateTodoDto: UpdateTodoDto) {
return this.todosService.update(id, updateTodoDto);
}
@Delete(':id')
remove(@Param('id') id: number) {
return this.todosService.remove(id);
}
然后在Dto中加上类型及校验
//create-todo.dto.ts
import { IsString, IsBoolean } from 'class-validator';
export class CreateTodoDto {
@IsString()
title: string;
@IsString()
content: string;
@IsBoolean()
isCompleted: boolean;
}
小心得。在实体类中,我们定义了id,title,content,isCompleted四个属性,为什么create-todo.dto.ts中只需要三个属性? 因为id是主键,每个数据的id都必须独一无二,因此这个工作应该是由数据库自己完成,而不是用户上传,因此前端的Dto不应该传入id
然后修改filter-todo.dto
import { IsEnum, IsInt, IsOptional } from 'class-validator';
enum OrderBy {
ASC = 'asc',
DESC = 'desc',
}
export class FilterTodoDto {
@IsInt()
@IsOptional()
page?: number;
@IsInt()
@IsOptional()
limit?: number;
@IsOptional()
@IsEnum(OrderBy)
orderBy?: OrderBy;
}