导图社区 NestJS基础知识
NestJS基础知识的思维导图,一起来学习: 入口[main.ts]、控制器(Controllers)、提供者(Providers/DI)、模块(Modules)、中间件(Middleware)、异常过滤器(Exception Filters)、管道(Pipes)、守卫(Guards)、拦截器(Interceptors)、自定义装饰器(Custom Decorators)、命令行 (Nest CLI)的内容。
编辑于2023-04-09 21:56:56 广东NestJS基础知识的思维导图,一起来学习: 入口[main.ts]、控制器(Controllers)、提供者(Providers/DI)、模块(Modules)、中间件(Middleware)、异常过滤器(Exception Filters)、管道(Pipes)、守卫(Guards)、拦截器(Interceptors)、自定义装饰器(Custom Decorators)、命令行 (Nest CLI)的内容。
这是一篇关于Webpack5.x入门的思维导图
PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言,且PHP 是免费的,使用非常广泛。
社区模板帮助中心,点此进入>>
NestJS基础知识的思维导图,一起来学习: 入口[main.ts]、控制器(Controllers)、提供者(Providers/DI)、模块(Modules)、中间件(Middleware)、异常过滤器(Exception Filters)、管道(Pipes)、守卫(Guards)、拦截器(Interceptors)、自定义装饰器(Custom Decorators)、命令行 (Nest CLI)的内容。
这是一篇关于Webpack5.x入门的思维导图
PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言,且PHP 是免费的,使用非常广泛。
NestJS基础知识
入口[main.ts]
NestFactory
create()
async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(3000); } bootstrap();
INestApplication
Platform
platform-express
NestExpressApplication
platform-fastify
NestFastifyApplication
const app = await NestFactory.create<NestExpressApplication>(AppModule);
控制器(Controllers)
路由机制
@Controller('cats')
代表/cats
@Get(:id)
代表/cats/:id
通配符(Route wildcards)
@Get('ab*cd')
匹配:abcd, ab_cd, abecd,等
子域名路由
@Controller({ host: 'admin.example.com' })
Fastify不支持
HTTP方法
@Get()
@Post()
@Put()
@Delete()
@Patch()
@Options()
@Head()
@All()
常用装饰器(方法参数)
@Request(), @Req()
@Get() findAll(@Req() request: Request): string { return 'This action returns all cats'; }
@Response(), @Res()*
@Next()
@Session()
@Param(key?: string)
@Body(key?: string)
@Query(key?: string)
@Headers(name?: string)
@Ip()
@HostParam()
状态码(Status code)
@HttpCode(204) 装饰器修改
Post返回201
其他返回200
返回头(Headers)
@Header('Cache-Control', 'none') 使用装饰器
@nestjs/common
使用平台相关方法 res.header()
重定向跳转(Redirection)
@Redirect('https://nestjs.com', 301)
默认跳转302状态码
res.redirect()
动态跳转
返回:{ "url": string, "statusCode": number }
异步(Asynchronicity)
Promise
@Get() async findAll(): Promise<any[]> { return []; }
Observable
@Get() findAll(): Observable<any[]> { return of([]); }
模块挂载
@Module({ controllers: [CatsController], }) export class AppModule {}
提供者(Providers/DI)
装饰器 @Injectable()
依赖注入(IOC/DI)
基于构造函数
constructor(private catsService: CatsService) {}
constructor(@Optional() @Inject('HTTP_OPTIONS') private httpClient: T) {}
基于属性
@Inject('HTTP_OPTIONS') private readonly httpClient: T;
模块挂载
@Module({ controllers: [CatsController], providers: [CatsService], })
模块(Modules)
属性
providers
由NestJS注入器实例化的提供者,至少在本模块共享(可以导出给其他模块使用)
controllers
本模块定义的需要实例化的控制器
imports
其他的模块,那些有导出提供者的模块,会被本模块使用到
exports
导出的提供者,会共享给其他模块,也就是其他模块的Imports属性需要登记的模块
共享模块
通过exports导出,其他模块通过Imports导入
依赖注入
模块能注入提供者,但是不能被提供者注入
@Module({ controllers: [CatsController], providers: [CatsService], }) export class CatsModule { constructor(private catsService: CatsService) {} }
全局模块
使用@Global()
@Global() @Module({ controllers: [CatsController], providers: [CatsService], exports: [CatsService], }) export class CatsModule {}
只能注册一次,一般是在根或者核心模块
也是需要在一个模块写入imports属性的,不是只要申明@Global
动态模块(Dynamic modules)
返回: { global: true, module: DatabaseModule, providers: providers, exports: providers, }
想注册为全局设置global:true
forRoot\forChildren\forXXXX
可设置不同级别的注册函数,也可以通过参数返回不同的providers\controllers\等
static forRoot(entities = [], options?): DynamicModule { const providers = createDatabaseProviders(options, entities); return { module: DatabaseModule, providers: providers, exports: providers, }; }
中间件(Middleware)
特性
在路由处理之前调用
可以访问request和response对象
可访问下一个中间件,通常为next为属性名
不调用next函数,请求将会被挂起
默认情况下Nest的中间件等同于express
功能
执行任意代码,修改request和response对象
结束request-response周期
调用下一个中间件
实现
@Injectable()
NestMiddleware
类形式
@Injectable() export class LoggerMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { console.log('Request...'); next(); } }
函数形式
export function logger(req: Request, res: Response, next: NextFunction) { console.log(`Request...`); next(); };
使用
MiddlewareConsumer
export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(LoggerMiddleware) .forRoutes('cats'); } }
缩小路由:.forRoutes({ path: 'cats', method: RequestMethod.GET });
排除:consumer .apply(LoggerMiddleware) .exclude( { path: 'cats', method: RequestMethod.GET }, { path: 'cats', method: RequestMethod.POST }, 'cats/(.*)', ) .forRoutes(CatsController);
多个中间件
consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);
全局中间件
const app = await NestFactory.create(AppModule); app.use(logger);
异常过滤器(Exception Filters)
全局捕获未处理异常
{ "statusCode": 500, "message": "Internal server error" }
基础异常类
HttpException
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
response
string/object
status
HTTP status code.
自定义异常
export class ForbiddenException extends HttpException { constructor() { super('Forbidden', HttpStatus.FORBIDDEN); } }
内置异常类
BadRequestException
UnauthorizedException
NotFoundException
ForbiddenException
NotAcceptableException
RequestTimeoutException
ConflictException
GoneException
HttpVersionNotSupportedException
PayloadTooLargeException
UnsupportedMediaTypeException
UnprocessableEntityException
InternalServerErrorException
NotImplementedException
ImATeapotException
MethodNotAllowedException
BadGatewayException
ServiceUnavailableException
GatewayTimeoutException
PreconditionFailedException
异常过滤器
功能更全,能够完全控制异常处理过程
@Catch(HttpException) export class HttpExceptionFilter implements ExceptionFilter { catch(exception: HttpException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const request = ctx.getRequest<Request>(); const status = exception.getStatus(); response .status(status) .json({ statusCode: status, timestamp: new Date().toISOString(), path: request.url, }); } }
使用@Catch(HttpException) 捕获特定的异常进行处理,捕获多种异常,使用逗号隔开
绑定过滤器
Controller级别
@UseFilters(new HttpExceptionFilter()) export class CatsController {}
方法级别
@Post() @UseFilters(new HttpExceptionFilter()) async create(@Body() createCatDto: CreateCatDto) { throw new ForbiddenException(); }
全局级别
app.useGlobalFilters(new HttpExceptionFilter());
@Module({ providers: [ { provide: APP_FILTER, useClass: HttpExceptionFilter, }, ], })
管道(Pipes)
实现
@Injectable()
PipeTransform
@Injectable() export class ValidationPipe implements PipeTransform { transform(value: any, metadata: ArgumentMetadata) { return value; } }
作用
数据转换
转换数据格式等
数据效验
符合效验规则通过,不符合抛出异常
内置管道
ValidationPipe
npm i --save class-validator class-transformer
ParseIntPipe
ParseFloatPipe
ParseBoolPipe
ParseArrayPipe
ParseUUIDPipe
ParseEnumPipe
DefaultValuePipe
ParseFilePipe
绑定管道
参数级
@Get(':id') async findOne(@Param('id', ParseIntPipe) id: number) { return this.catsService.findOne(id); }
Controller级
@UsePipes(new JoiValidationPipe(createCatSchema))
全局
app.useGlobalPipes(new ValidationPipe());
@Module({ providers: [ { provide: APP_PIPE, useClass: ValidationPipe, }, ], })
守卫(Guards)
守卫会在路由处理之前执行,决定这个请求是否会被接受,根据一些规则,比如说权限,角色,控制列表等
实现
@Injectable()
CanActivate
@Injectable() export class AuthGuard implements CanActivate { canActivate( context: ExecutionContext, ): boolean | Promise<boolean> | Observable<boolean> { const request = context.switchToHttp().getRequest(); return validateRequest(request); } }
返回
返回true处理用户请求
返回false拒绝用户请求
执行环境(Execution context)
ExecutionContext
继承自ArgumentsHost
getHandler()
返回要被调用的处理函数引用
getClass()
返回这个controller的类型
export interface ExecutionContext extends ArgumentsHost { /** * Returns the type of the controller class which the current handler belongs to. */ getClass<T>(): Type<T>; /** * Returns a reference to the handler (method) that will be invoked next in the * request pipeline. */ getHandler(): Function; }
@SetMetadata()装饰器
有时候一些方法不需要guard守卫,就需要设置一些开关来跳过验证
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) { // See this condition return true; }
使用
Controller/方法级别
@UseGuards(AuthGuard)
全局
app.useGlobalGuards(new RolesGuard());
providers: [ { provide: APP_GUARD, useClass: AuthGuard, }, ],
拦截器(Interceptors)
实现
@Injectable()
NestInterceptor
@Injectable() export class LoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { console.log('Before...'); const now = Date.now(); return next .handle() .pipe( tap(() => console.log(`After... ${Date.now() - now}ms`)), ); } }
作用
在处理函数执行前后绑定而外的逻辑
转换函数处理结果
转换处理函数抛出的异常
扩展函数表现行为
重新一个函数处理逻辑,根据一定的条件,比如说缓存
intercept()
ExecutionContext
CallHandler
路由执行函数
执行完成返回Observable进行之后的逻辑处理
绑定
Controller/方法级
@UseInterceptors(LoggingInterceptor)
全局
app.useGlobalInterceptors(new LoggingInterceptor());
@Module({ providers: [ { provide: APP_INTERCEPTOR, useClass: LoggingInterceptor, }, ], }) export class AppModule {}
自定义装饰器(Custom Decorators)
主要作用是添加一些额外的数据
实现
export const User = createParamDecorator( (data: unknown, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return request.user; }, );
使用
@Get() async findOne(@User() user: UserEntity) { console.log(user); }
配合pipe一起使用
@User(new ValidationPipe({ validateCustomDecorators: true }))
聚合装饰器
export function Auth(...roles: Role[]) { return applyDecorators( SetMetadata('roles', roles), UseGuards(AuthGuard, RolesGuard), ApiBearerAuth(), ApiUnauthorizedResponse({ description: 'Unauthorized' }), ); }
命令行 (Nest CLI)
安装
$ npm install -g @nestjs/cli
基础命令
nest --help
nest generate --help
nest new my-nest-project
生成nest g
app Generate a new application within a monorepo (converting to monorepo if it's a standard structure).
library lib Generate a new library within a monorepo (converting to monorepo if it's a standard structure).
class cl Generate a new class.
controller co Generate a controller declaration.
decorator d Generate a custom decorator.
filter f Generate a filter declaration.
gateway ga Generate a gateway declaration.
guard gu Generate a guard declaration.
interface itf Generate an interface.
interceptor itc Generate an interceptor declaration.
middleware mi Generate a middleware declaration.
module mo Generate a module declaration.
pipe pi Generate a pipe declaration.
provider pr Generate a provider declaration.
resolver r Generate a resolver declaration.
resource res Generate a new CRUD resource. See the CRUD (resource) generator for more details.
service s Generate a service declaration.
NestJS
Controller
import { Controller } from '@nestjs/common';
response methods
standard
return
recommend
Library-specific
findAll(@Res() response)
request
@Req() request: Request
CURD
@Get(), @Post(), @Put(), @Delete(), @Patch(), @Options(), and @Head(). In addition, @All()
Decorators
@Header()
@Redirect()
@HttpCode()
@Query
@Param
Route Parameters
@Get(':id') findOne(@Param() params): string { console.log(params.id); return `This action returns a #${params.id} cat`; }
DTO
@Post() async create(@Body() createCatDto: CreateCatDto) { return 'This action adds a new cat'; }
HttpStatus
@nestjs/common
Providers
import { Injectable } from '@nestjs/common';
@Injectable()
constructor(private catsService: CatsService) {}
register
@Module({ controllers: [CatsController], providers: [CatsService], })
Optional
import { Injectable, Optional, Inject } from '@nestjs/common'; @Injectable() export class HttpService<T> { constructor(@Optional() @Inject('HTTP_OPTIONS') private httpClient: T) {} }
Property Based Inject
import { Injectable, Inject } from '@nestjs/common'; @Injectable() export class HttpService<T> { @Inject('HTTP_OPTIONS') private readonly httpClient: T; }
Modules
import { Module } from '@nestjs/common';
@Module()
providers
controllers
imports
exports
Feature modules
Global modules
singletons
Dynamic modules
Custom decorators
Interceptors
export class LoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { console.log('Before...'); const now = Date.now(); return next .handle() .pipe( tap(() => console.log(`After... ${Date.now() - now}ms`)), ); } }
@UseInterceptors
useGlobalInterceptors
Guards
CanActivate
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Observable } from 'rxjs'; @Injectable() export class RolesGuard implements CanActivate { canActivate( context: ExecutionContext, ): boolean | Promise<boolean> | Observable<boolean> { return true; } }
@UseGuards(RolesGuard)
Pipes
A pipe is a class annotated with the @Injectable() decorator. Pipes should implement the PipeTransform interface.
use cases
validation
transformation
ValidationPipe ParseIntPipe ParseFloatPipe ParseBoolPipe ParseArrayPipe ParseUUIDPipe ParseEnumPipe DefaultValuePipe
use
@Get(':id') async findOne(@Param('id', ParseIntPipe) id: number) { return this.catsService.findOne(id); }
custom
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common'; @Injectable() export class ValidationPipe implements PipeTransform { transform(value: any, metadata: ArgumentMetadata) { return value; } }
global
async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe()); await app.listen(3000); } bootstrap();
default pipe
@Get() async findAll( @Query('activeOnly', new DefaultValuePipe(false), ParseBoolPipe) activeOnly: boolean, @Query('page', new DefaultValuePipe(0), ParseIntPipe) page: number, ) { return this.catsService.findAll({ activeOnly, page }); }
Exception filters
Built-in HTTP exceptions
@Catch(HttpException)
Arguments host#
Binding filters
@Post() @UseFilters(new HttpExceptionFilter()) async create(@Body() createCatDto: CreateCatDto) { throw new ForbiddenException(); }
useGlobalFilters
async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new HttpExceptionFilter()); await app.listen(3000); } bootstrap();
Method-scoped and Controller-scoped filters that extend the BaseExceptionFilter should not be instantiated with new. Instead, let the framework instantiate them automatically.
Middleware
next
custom middleware
function
class
implements NestMiddleware
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @Injectable() export class LoggerMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { console.log('Request...'); next(); } }
Apply
import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common'; import { LoggerMiddleware } from './common/middleware/logger.middleware'; import { CatsModule } from './cats/cats.module'; @Module({ imports: [CatsModule], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(LoggerMiddleware) .forRoutes({ path: 'cats', method: RequestMethod.GET }); } }
MiddlewareConsumer
exclude
consumer .apply(LoggerMiddleware) .exclude( { path: 'cats', method: RequestMethod.GET }, { path: 'cats', method: RequestMethod.POST }, 'cats/(.*)', ) .forRoutes(CatsController);
Functional middleware
Multiple middleware
consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);
DI
@Injectable()
@Inject()
registration
useValue
Execution Context
ArgumentsHost
getType()
getArgs()
/** * Switch context to RPC. */ switchToRpc(): RpcArgumentsHost; /** * Switch context to HTTP. */ switchToHttp(): HttpArgumentsHost; /** * Switch context to WebSockets. */ switchToWs(): WsArgumentsHost;
ExecutionContext
const methodKey = ctx.getHandler().name; // "create" const className = ctx.getClass().name; // "CatsController"
const roles = this.reflector.getAllAndOverride<string[]>('roles', [ context.getHandler(), context.getClass(), ]);
主要概念
Providers
DI Provider
Middleware
Filters
Pipe
Guards
Interceptors
Best Practices
Validations
Class Validator
Validation decorators
Mapped types
PartialType
PickType()
OmitType
IntersectionType
ParseArrayPipe
Clean Architecture
Clean architecture with Nestjs
Clean Node.js Architecture —With NestJs and TypeScript
主题
FAQ
PIPE VS
Upload Files
Nestjs file uploading using Multer
Deployment
NestJS后台架构
Authentication
Password-jwt/passowrd-local with cookies
bcrypt
set jwt in cookie use httponly
Authorization
roles/permissions guards
HTTP
Filters
Exceptions
DTO
Database
Pagination
Logger
CORS
Resources
使用NestJS设计API
Multi-tenancy
nest-admin
Security
Authentication
JWT
npm install --save @nestjs/passport passport
npm install --save-dev @types/passport-jwt
npm install --save @nestjs/jwt passport-jwt
Session
OAuth
protect routes
Authorization
CASL
Casbin
AccessControl
手摸手,带你实现Nestjs接口权限控制
主题
Swagger
Install
npm install --save @nestjs/swagger swagger-ui-express
setup
import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); const config = new DocumentBuilder() .setTitle('Cats example') .setDescription('The cats API description') .setVersion('1.0') .addTag('cats') .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api', app, document); await app.listen(3000); } bootstrap();
@ApiProperty
主题
MongoDB
typegoose
mongoose
npm install --save @nestjs/mongoose mongoose
timestamps
created_at updated_at
connection
exec vs await
if use exec method it will return a promise, if without it you get a thenable return object.
@nestjs/mongoose
@schema
options
@Prop()
raw
@Prop(raw({ firstName: { type: String }, lastName: { type: String } })) details: Record<string, any>;
alias filed
options
Schema Types
specify relation
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Owner' }) owner: Owner;
@Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Owner' }] }) owner: Owner[];
MongooseModule
forRoot
accept same configuration of mongoose.connect()
@InjectModel()
Plugins
SchemaTypes
Populate
Populating Maps
$*
seeding
Seeding Databases Using NestJS