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> -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
的依赖注入到其构造函数中用以拆分业务逻辑并在内部使用
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);}