NestJs
官方基础课程(快速体验)
快速创建nest项目
全局安装nest
1 | npm i -g nest |
快速创建nest项目
1 | nest new |
创建出来目录结构:
- main.js 主入口
- app.module.ts 创建的控制器会被controllers集成
- app.service.ts
- app.controller.ts
生成controller
1 | nest generate controller controllerName |
nuxt开发时热更新命令:
1 | npm run start:dev |
控制器 Controller
定义映射器类
/coffee
1 | 'coffee') ( |
/coffee/flavors
1 | 'coffee') ( |
/coffee/123456
1 | 'coffee') ( |
/coffee/create
1 | 'coffee') ( |
/coffee/yummy
1 | 'coffee') ( |
更新数据
/coffee/1234
1 | 'coffee') ( |
删除数据
/coffee/1234
1 | 'coffee') ( |
服务 Service|Provider
1 | nest generate service |
service会被创建在src对应路径下,
同时更新在app.modules.ts下的providers数组中
每个Service都是一个provider,
- provider内可以注入依赖
- provider可以作为依赖被注入到controller中
service负责处理数据存储、检索等工作,
为controller提供数据。
创建实体,作为service控制的对象:
nest中将controller和service集成在同一个目录下,
entity实体也创建在此目录下。
/src/coffee/entities/coffee.entity.ts
1 | export class Coffee{ |
1 | import { Injectable } from '@nestjs/common'; |
在controller中通过构造函数,注入service:
1 | 'coffee') ( |
1 | () |
模块 Module
集成module
1 | nest g module moduleName |
在app.modules.ts横纵的imports内会自动引入新创建的Module
使用module将controllers和providers集成在一起:
1 | import { Module } from '@nestjs/common'; |
将app.module.ts的代码清理一下,保证controller和service仅被实例化一次:
1 | import { Module } from '@nestjs/common'; |
DTO
data transfer object
用于封装规范接口传输的数据类型
生成DTO
1 | nest g class className |
dto的定义:
create-coffee.dto.ts
1 | export class CreateCoffeeDto { |
dto的使用:
coffee.controller.ts
1 | 'coffee') ( |
数据验证要用到ValidationPipe
需要下载如下包:
1 | npm i class-validator class-transformer @nestjs/mapped-types |
在main.ts中加入pipe
- whitelist 白名单模式
- forbidNonWhitelisted 非白名单数据报错
- transform 将传入数据转化为指定的数据类型
1 | import { NestFactory } from '@nestjs/core'; |
在DTO中加入数据验证描述符:
1 | // create-coffee.dto.ts |
使用mapped-types包,
实现数据验证的继承与附加属性配置:
1 | import {PartialType} from '@nestjs/mapped-types' |
Docker
根目录下配置docker-compose.yml文件:
1 | version: "3" |
启动镜像:
1 | docker-compose up -d |
1 | { |
ORM
安装orm相关包:
- @nestjs/typeorm typeorm
- pg postgres相关包
1
npm i @nestjs/typeorm typeorm pg
app.module.ts中引入TypeOrmModule:
1 | import { TypeOrmModule } from '@nestjs/typeorm'; |
将之前仅作为接口类型约束的entities下的实体定义文件,进行ORM模型化:
1 | import {Entity, PrimaryGeneratedColumn, Column} from 'typeorm' |
在cake子模块中注册内部实现的实体:
1 | ({ |
创建好Entity之后,ORM模型会自动映射成为数据库表,
在service中作为数据库进行关联:
1 | () |
将之前的CURD操作对象迁移到数据库上:
查询
- find 查询所有
- findOne 查询指定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* 查找全部
*/
findAll(){
return this.cakeRepository.find()
}
/**
* 查找指定蛋糕
*/
async findOne(id:number){
const cake = await this.cakeRepository.findOne({
where:{
id:id
}
})
// let cake = this.cakes.find(item=>item.id == id)
if(!cake){
throw new NotFoundException(`Cake #${id} is not find`)
}
return cake
}
新增
- create 创建
- save 保存
1
2
3
4
5
6
7
8/**
* 新增蛋糕
* @param cake
*/
async create(createCakeDto: CreateCakeDto){
const cake = this.cakeRepository.create(createCakeDto)
return this.cakeRepository.save(cake)
}
更新
- preload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/**
* 修改蛋糕
* @param id
* @param cake
*/
async update(id:number, updateCoffeeDto:UpdateCakeDto){
// preload 更新 找不到指定id返回undefined
const cake = await this.cakeRepository.preload({
id:id,
...updateCoffeeDto
})
if(!cake){
throw new NotFoundException(`Cake #${id} is not exit`)
}
return this.cakeRepository.save(cake)
}
- preload
删除
- remove
1
2
3
4
5
6
7
8/**
* 删除蛋糕
* @param cake
*/
async delete(id: number){
const cake = await this.findOne(id)
return this.cakeRepository.remove(cake)
}
- remove
Relation
表间关联类型:
- @OneToOne()
- @OneToMany()
- @ManyToOne()
- @ManyToMany()
关联操作:
- 创建关系
创建一个新的Entity:Flavors,表示风味
1
nest g class cake/entities/flavor.entity --no-spec
新表加入模块定义中
1
@Module({ imports:[TypeOrmModule.forFeature([Cake,Flavor])] })
使用描述符对cake.flavors进行关联:
- @JoinTable() 标识关联属性所有者
1
2
3
4
5
6
7@JoinTable()
@ManyToMany(
type => Flavor, // 关联表类型
flavor => flavor.cakes, // 反向收集
{ cascade:true } // 级联关系
)
flavors: Flavor[];在被关联表中进行关联配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15()
export class Flavor {
()
id: number;
()
name: string;
(
type => Cake,
cake => cake.flavors
)
cakes: Cake[]
}
- 关联查询:
1 | findAll(){ |
- 级联插入
cake作为关系拥有表,当用新的flavor创建新的cake时,
新的flavor数据也会被级联创建
1 | /** |
PaginationQueryDto
- 为分页查询参数创建dto
1 | nest g class common/dto/pagination-query.dto --no-spec |
1 | import { IsOptional, IsPositive } from "class-validator"; |
可以在ValidationPipe中,配置强制类型转换:
1 | app.useGlobalPipes(new ValidationPipe({ |
- 修改controller和service中查询配置
1 | // 查询所有蛋糕 |
1 | /** |
Transaction 事务
事务:一组操作作为一个整体,要么全部执行成功,要么全部不执行
使用事务控制,在service中声明typeorm.DataSource类属性:
1 | // 关联数据库 |
使用QueryRunner和try/catch/finally进行事务处理:
1 | // 推荐蛋糕 |
数据库迁移
首先需要在根目录下创建ormconfig.ts文件:
1 | import { DataSource } from 'typeorm'; |
create 创建迁移脚本:
1
npx typeorm migration:create ./src/migrations/CoffeeRefactor
generate 生成迁移脚本
1
npx typeorm migration:generate ./src/migrations/CoffeeRefactor -d ./dist/ormconfig.js
run 运行迁移脚本
1
npx typeorm migration:run -d ./dist/ormconfig.js
revert 恢复
1
npx typeorm migration:revert -d ./dist/ormconfig.js
对要修改的表对应的ORM进行修改,
再在生成的迁移文件中进行表操作:
1 | // 实体类描述符 |
1 | import { MigrationInterface, QueryRunner } from "typeorm"; |
依赖注入 Dependency Injection
应用配置 Application Configuration
Next其它功能模块
Exception Filters 异常过滤器
Exception Filters用于处理应用中可能出现的异常
Pipes 管道
Pipes用于对输入的数据进行验证/转换
Guards 守卫
Guards用于对访问的用户进行身份验证
Interceptors 拦截器
Interceptors用于在接收到请求之前进行一些特殊操作