createParamDecorator(): Custom Parameter Decorators & Metadata Extraction
- Last updated
- Prerequisites:
- NestJS ExecutionContext
- TypeScript Parameter Decorators
- nestjs
- decorators
- createParamDecorator
- param-extraction
- clean-code
Read at your depth
The practical view
`createParamDecorator()` creates custom parameter decorators in NestJS. `export const User = createParamDecorator((data: string, ctx: ExecutionContext) => { const req = ctx.switchToHttp().getRequest(); return data ? req.user?.[data] : req.user; })`. In your controller, you can write `@Get() getProfile(@User() user: UserEntity, @User('id') userId: string)`.
The same idea in other frameworks
`export const User = createParamDecorator((data, ctx) => ...)`.FastAPI `Depends()` parameter dependency injection (`user: User = Depends(get_current_user)`).Spring `@AuthenticationPrincipal UserDetails user` or custom `HandlerMethodArgumentResolver`.Manually reading `req.user` inside controller handlers.Legacy vs modern
Manual @Req() Inspection vs Declarative @User() Param Decorator
Extracting properties manually from `@Req()` couples controllers to Express; `@User()` creates clean, typed parameters.
getProfile(@Req() req: any) { const user = req.user; // ❌ Directly coupled to ExpressgetProfile(@User('id', ParseIntPipe) userId: number) { // ✅ NEW: Clean, typed, pipeableInterview gotchas
Context
Interviewers test your knowledge of parameter evaluation pipelines in NestJS.
The mechanical answer
Yes. Custom parameter decorators integrate directly into the NestJS Pipe pipeline: `@Get() findOne(@User('id', ParseUUIDPipe) userId: string)`. NestJS first extracts the value using your custom decorator function, and then passes the extracted return value directly into `ParseUUIDPipe` for validation before the controller method runs.
Trap
The pipe receives the *extracted* value from the decorator, not the full request object.
Context
Checks unit testing and software engineering best practices.
The mechanical answer
When a controller method uses `@Req() req: Request`, unit tests must construct a massive mock Express `Request` object with headers, cookies, and socket properties. When using `@User() user: UserEntity`, unit tests can invoke the controller method directly as a plain JavaScript function with a simple object payload: `controller.getProfile({ id: '123' })`.
Trap
Avoid using `@Req()` or `@Res()` in controllers unless you need low-level socket or streaming control.