Controller
HTTP Requestを処理するやつ
@Controller()をクラス定義前に付ける@Controller('cats')
export class CatsController {上記の例は
/catsがパスになるGETメソッドの定義
@Get()
findAll(): string {
return 'This action returns all cats';
}@Get('breed')だとパスは/cats/breedになるRoute handlerでは、JSのobjectかarrayを返す場合は、レスポンスは自動的にJOSNにシリアライズされる。プリミティブを返す場合は、そのままレスポンスされる。Route handlerに渡されるRequestオブジェクトはexpressのやつimport { Request } from 'express';@Controller('cats')
export class CatsController {
@Get()
findAll(@Req() request: Request): string {
return 'This action returns all cats';
}
}Route handlerの引数にdecoratorをつければ、いろいろな情報を取ってこれる。@Req()@Res()@Next()@Session()@Param(key?: string)@Body(key?: string)@Query(key?: string)@Headers(name?: string)@Ip()@HostParam()
Provider
Service,Respository,Factory,Helperなどの総称ProviderはModuleに登録すると使える@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class AppModule {}
Service
DBなどからデータをとってくるやつ
@Injectable()をクラス定義に付ける@Injectable()
export class CatsService {Controllerのコンストラクタの引数にすればインスタンスを注入できる@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
Module
アプリを構造化するやつ
@Moduleをクラス定義につける@Module({
controllers: [CatsController],
providers: [CatsService],
imports: [...],
exports: [...],
})
export class CatsModule {}
MiddleWare
HTTPリクエストの処理の前に付けるやつ
関数でもクラスでも作成できる
クラスの例
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Request...');
next();
}
}Moduleのconfigureメソッドで注入できる@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware) // Middlewareを登録
.forRoutes('cats'); // `/cats`パスにMiddlewareを適用
}
}forRoutesにControllerを渡してもよい.forRoutes(CatsController);Fuctional middlewareの例次の引数も持ったただの関数
export function logger(req: Request, res: Response, next: NextFunction) {
console.log(`Request...`);
next();
};以下のように適用する
consumer
.apply(logger)
.forRoutes(CatsController);
Pipe
Route handlerの引数に適用して、引数の変換やバリデーションを行うやつビルトインの
ParseIntPipeの使用例@Get(':id')
async findOne(@Param('id', ParseIntPipe) id: number) {
return this.catsService.findOne(id);
}インスタンス化を自分ですることもできる
@Get(':id')
async findOne(
@Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }))
id: number,
) {
return this.catsService.findOne(id);
}Pipeの処理が失敗すると例外を投げるCustom pipeの例@Injectable()
export class ValidationPipe<T, R> implements PipeTransform<T, R> {
transform(value: T, metadata: ArgumentMetadata): R { // 必須メソッド
return convert(value);
}
}valueはPipeを適用する関数の引数ArgumentMetadataは以下の情報を持っているexport interface ArgumentMetadata {
type: 'body' | 'query' | 'param' | 'custom';
metatype?: Type<unknown>;
data?: string;
}
Guard
Route handlerの前に作用して、そのRoute handlerを実行するかしないかを決定するやつMiddlewareに比べて、どのRoute handlerに適用されるのか詳細に設定できるよく認証の確認に使われる
@Injectable()
export class AuthGuard implements CanActivate {
// 必須のメソッド
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return validateRequest(request);
}
}Guardの適用@Controller('cats')
@UseGuards(RolesGuard)
export class CatsController {}@UseGuardsはController内のメソッドにも適用できるGuard内で対象のRoute handlerに付けられたdecoratorを参照することが可能Route handlerに付けるCustom decoratorの作成:export const Roles = Reflector.createDecorator<string[]>();RolesをRoute handlerに適用する:@Post()
@Roles(['admin'])
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}RolesをGuardから参照する:@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
// ExecutionContextからRolesを取得できる
const roles = this.reflector.get(Roles, context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
return matchRoles(roles, user.roles);
}
}
Interceptor
Route handlerの前後に処理を挟むことができるやつNestInterceptorを継承するintercept()メソッドを実装するintercept()メソッドの引数はExecutionContextとCallHandlerの2つCallHandlerはRoute handlerのことintercept()メソッドの中でCallHandlerを実行しないと、Route handlerは実行されないLoggingInterceptorの例@Injectable()
export class LoggingInterceptor implements NestInterceptor<T, R> {
intercept(context: ExecutionContext, next: CallHandler): Observable<R> {
console.log('Before...');
const now = Date.now();
return next
.handle() // Observale<T>
.pipe(
tap(() => console.log(`After... ${Date.now() - now}ms`)),
);
}
}Interceptorの適用@UseInterceptors(LoggingInterceptor)
export class CatsController {}メソッドレベルにも適用できる