ArgumentsHost Current application contextHost Handler argumentsExecutionContext Reflection and metadata
ArgumentsHost
export interface ArgumentsHost {
getArgs<T extends Array<any> = any[]>(): T;
getArgByIndex<T = any>(index: number): T;
switchToRpc(): RpcArgumentsHost;
switchToHttp(): HttpArgumentsHost;
switchToWs(): WsArgumentsHost;
getType<TContext extends string = ContextType>(): TContext;
}
- 핸들러에 전달되는 인수를 검사하는 메서드 제공
- 적절한 context(HTTP, RPC, WebSocket)를 선택하여 param을 사용할 수 있다.
- HTTP 애플리케이션의 경우, exception filter의 catch()문에서 다음과 같이 사용할 수 있다.
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
...
}
}
Current application context
- generic guards, filter, interceptors를 사용할 때 메서드가 현재 실행 중인 애플리케이션 유형을 판단할 경우, ArgumentHost의
getType()
을 사용할 수 있다.
if (host.getType() === 'http') {
// do something that is only important in the context of regular HTTP requests (REST)
} else if (host.getType() === 'rpc') {
// do something that is only important in the context of Microservice requests
} else if (host.getType<GqlContextType>() === 'graphql') {
// do something that is only important in the context of GraphQL requests
}
Host Handler arguments
- getArgs()로 req, res를 얻어올 수있다.
const [req, res, next] = host.getArgs();
const request = host.getArgByIndex(0);
const response = host.getArgByIndex(1);
switchToHttp
,switchToRpc
,switchToWs
를 사용하여 애플리케이션 컨텍스트를 전환할 수 있다.
/**
* Switch context to RPC.
*/
switchToRpc(): RpcArgumentsHost;
/**
* Switch context to HTTP.
*/
switchToHttp(): HttpArgumentsHost;
/**
* Switch context to WebSockets.
*/
switchToWs(): WsArgumentsHost;
ExecutionContext
- ExecutionContext는 ArgumentHost를 상속받고, 현재 프로세스에 대한 추가 세부 정보를 제공한다.
export interface ExecutionContext extends ArgumentsHost {
getClass<T = any>(): Type<T>;
getHandler(): Function;
}
const methodKey = ctx.getHandler().name; // "create"
const className = ctx.getClass().name; // "CatsController"
Reflection and metadata
- Nest는
Reflector.createDecorator()
로 데코레이터를 생성하고 메서드를@SetMetadata()
로 매핑하는 기능을 이용해 custom metadata를 route handler에 매핑한다.
- Reflection 사용 예시
// roles.decorator.ts
import { Reflector } from '@nestjs/core';
export const Roles = Reflector.createDecorator<string[]>();
// roles.guard.ts
@Injectable()
export class RolesGuard {
constructor(private reflector: Reflector) {}
}
// cats.controller.ts
@Post()
@Roles(['admin']) // => Roles가 admin인 유저만 create를 허용
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
reflector.get(decorator, context)
context
는context.getHandler()
를 통해 얻음
- 다음과 같이 Roles를 method 레벨과 컨트롤러 레벨에서 같이 사용하는 경우
// cats.controller.ts
@Roles(['user'])
@Controller('cats')
export class CatsController {
@Post()
@Roles(['admin'])
async create1(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
@Post()
async create2(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
}
// roles.guard.ts
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles1 = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
console.log("requiredRoles: ", requiredRoles1)
const requiredRoles2 = this.reflector.getAllAndMerge(ROLES_KEY, [context.getHandler(), context.getClass()]);
console.log("requiredRoles: ", requiredRoles2)
}
}
reflector.
getAllAndOverride(metadataKey, targets)
- 위 경우, create1() 에서는 requiredRoles이 [’Admin’],
- create2() 에서는 requiredRoles이 [‘User’]가 된다.
reflector.
getAllAndMerge(metadataKey, targets)
- 위 경우, create1()에서는 requiredRoles이 [’Admin’, ‘User’]
- 위 경우, create2()에서는 requiredRoles이 [‘User’]가 된다.
- Roles()로 할당하지 않고,
@SetMetadata(ROLES_KEY, ['admin'])
이런식으로 할당하는것도 가능하다.
@Post('test2')
@SetMetadata('roles', ['test'])
@UseGuards(RolesGuard)
async create3(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
Share article