Nestjs-学习笔记

/post/nest-basic article cover image

Nestjs作为一个在nodejs框架(expressfastify、...)之上的抽象层提供了可扩展、可测试、多样性(rest apimicroservicesweb socketsgraphql)、渐进式的架构解决方案,可以满足各种后端的需求场景

基础

cli

nest cli提供了系列模板代码创建以及启动、打包命令

shell
pnpm add -g @nest/cli

// 创建nest项目-new
nest new project-name

// 启动项目-start
nest start | start:dev

// 构建项目-build
nest build

// 查看项目详情-info
nest info

// 导入外部嵌套库
nest add xxx

// 生成模板代码-generate
nest generate controller | module | middleware | ...

// 查看所有|指定命令
nest -h
nest <command> -h

controller

controller作为mvc模型中逻辑的最小单元nest为此提供了很多便利修饰符以供使用

ts
/* import { ... } from "@nestjs/common" */

// 一级路由构成: http://localhost:3000/things
@Controller('things')
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  findAll(): string {
    return 'This action return all things'
  }

  // 使用分页查询: http://localhost:3000/things?limit=10&offset=0
  @Get()
  findPartial(@Query() paginationQuery) {
    const { limit, offset } = paginationQuery;
    return `This action returns partion things. Limit: ${limit} Offset: ${offset}`;
  }

  // 路由参数: http://localhost:3000/hello/123
  @Get(':id')
  findOne(@Param('id') id:string) {
    return `This action returns #${id} one`
  }

  // 返回传递过来的body
  @Post()
  @HttpCode(HttpStatus.OK)
  create(@Body() body) {
    return body;
  }

  // 使用框架风格返回
  @Get()
  findAllUsePlatform(@Res() res) {
    res.status(200).send('This action returns all things');
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() body) {
    return ''
  }
}

providers

provider(services、repositories、helpers、etc)作为controller的依赖注入到其构造函数中用以拆分业务逻辑并在内部使用

ts
import { ThingsService } from "./things.service.ts"

@Controller('things') mk
export class ThingsController {
  construct(private readonly thingsService: ThingsService) {}
  findAll() {
    return this.thingsService.findAll();
  }
  // ...
}
ts
export class Things {
  id: number;
  name: string;
  brand: string;
  flavors: string[];
}
ts
import { Things } from "../entities/things.entity.ts"
export class ThingsService {
  private things: Things[] = [
    {
      id: 1,
      name: 'Auu',
      brand: 'someone',
      flavors: ['a', 'b'],
    },
  ];
  findAll() {
    return this.things;
  }
  // ...
}

modules

@Module是用来聚合一个业务模块所需要的关联组件(controller、provider)又可以通过imports来复用其他模块的入口层用以拆分业务模块,每个应用至少有一个根模块

ts
@Module({
  imports: [CoffeesModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
ts
@Module({
  controllers: [ThingsController],
  providers: [ThingsService],
})
export class ThingsModule {}

dto

DTO(data transfer object)用来规定api入参及返回数据的形式及类型接口,通过useGlobalPipes搭配class-validator以解决类型安全及参数校验一旦参数不满足则返回400状态提示

ts
import { IsString } from 'class-validator';
export class CreateSomeThingDto {
  @IsString()
  readonly name: string;
  @IsString()
  readonly brand: string;
  @IsString({ each: true })
  readonly flavors: string[];
}

使用@nestjs/mapped-types对于现有DTO字段规则进行复用

ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateSomeThingDto } from './create-something.dto';
export class UpdateSomeThingDto extends PartialType(CreateSomeThingDto) {}
ts
@Post()
create(@Body() createCoffeeDto: CreateCoffeeDto) {
  return this.coffeesService.create(createCoffeeDto);
}
ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,            // 忽略dto指定外的字段
    transform: true,            // 转换入参为指定类型用以匹配对应的DTO
    forbidNonWhitelisted: true, // 禁止dto指定外的字段,会有400提示
  }));
  await app.listen(3000);
}

dependency-injection

范式约定

  • 对于api风格的推荐使用非特定框架写法
ts
findSomeTHing() {
  return 'xxx';
}
  • 对于api错误信息推荐使用Expection Layer返回特定场景的错误提示
ts
if (!something) {
  throw new HttpException(`SomeThing not found`, HttpStatus.NOT_FOUND);
}