In nest.js, is it possible to get service instance inside a param decorator?
for NestJS v7
Create custom pipe
// parse-token.pipe.ts
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
import { AuthService } from './auth.service';
@Injectable()
export class ParseTokenPipe implements PipeTransform {
// inject any dependency
constructor(private authService: AuthService) {}
async transform(value: any, metadata: ArgumentMetadata) {
console.log('additional options', metadata.data);
return this.authService.parse(value);
}
}
Use this pipe with property decorator
// decorators.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { ParseTokenPipe} from './parse-token.pipe';
export const GetToken = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
return ctx.switchToHttp().getRequest().header.Authorization;
});
export const Principal = (additionalOptions?: any) => GetToken(additionalOptions, ParseTokenPipe);
Use this decorator with or without additional options
@Controller('/test')
class TestController {
@Get()
get(@Principal({hello: "world"}) principal) {}
}
It is not possible to inject a service into your custom decorator.
Instead, you can create an AuthGuard
that has access to your service. The guard can then add a property to the request
object, which you can then access with your custom decorator:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const bearerToken = request.header.Authorization;
const user = await this.authService.authenticate(bearerToken);
request.principal = user;
// If you want to allow the request even if auth fails, always return true
return !!user;
}
}
import { createParamDecorator } from '@nestjs/common';
export const Principal = createParamDecorator((data: string, req) => {
return req.principal;
});
and then in your controller:
@Get()
@UseGuards(AuthGuard)
get(@Principal() principal: Principal) {
// ...
}
Note that nest offers some standard modules for authentication, see the docs.