Nestjs-学习笔记
nodejsserver architecture
Nestjs作为一个在nodejs框架(express、fastify、...)之上的抽象层提供了可扩展、可测试、多样性(rest api、microservices、web sockets、graphql)、渐进式的架构解决方案,可以满足各种后端的需求场景
基础
CLI
nest cli提供了系列模板代码创建以及启动、打包命令
shell
pnpm add -g @nest/cli
// 创建nest项目-newnest new project-name
// 启动项目-startnest start | start:dev
// 构建项目-buildnest build
// 查看项目详情-infonest info
// 导入外部嵌套库nest add xxx
// 生成模板代码-generatenest generate controller | module | middleware | ...
// 查看所有|指定命令nest -hnest <command> -hController
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的依赖注入到其构造函数中用以拆分业务逻辑并在内部使用
controller.ts
ts
import { ThingsService } from "./things.service.ts"
@Controller('things') mkexport class ThingsController { construct(private readonly thingsService: ThingsService) {} findAll() { return this.thingsService.findAll(); } // ...}things.entity.ts
ts
export class Things { id: number; name: string; brand: string; flavors: string[];}things.service.ts
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来复用其他模块的入口层用以拆分业务模块,每个应用至少有一个根模块
app.module.ts
ts
@Module({ imports: [CoffeesModule], controllers: [AppController], providers: [AppService],})export class AppModule {}things.module.ts
ts
@Module({ controllers: [ThingsController], providers: [ThingsService],})export class ThingsModule {}DTO
DTO(data transfer object)用来规定api入参及返回数据的形式及类型接口,通过useGlobalPipes搭配class-validator以解决类型安全及参数校验一旦参数不满足则返回400状态提示
createSomeThing.dto.ts
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字段规则进行复用
updateSomeThing.dto.ts
ts
import { PartialType } from '@nestjs/mapped-types';import { CreateSomeThingDto } from './create-something.dto';export class UpdateSomeThingDto extends PartialType(CreateSomeThingDto) {}things.controller.ts
ts
@Post()create(@Body() createCoffeeDto: CreateCoffeeDto) { return this.coffeesService.create(createCoffeeDto);}main.ts
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);}