@nest-extended/decorators

Small, reusable decorators that standardise controller behaviour — reading the current user, marking routes public, transforming the request body, and running logic around a route handler.

$npm install @nest-extended/decorators

Key exports

ExportTypePurpose
@User()param decoratorInject the authenticated req.user
@Public()method decoratorMark a route public (skip the auth guard)
@ModifyBody(...fns)param decoratorTransform the request body before it reaches the handler
setCreatedBy(key?)modifierStamp the current user id onto a body field (createdBy by default)
@UseBefore(...handlers)method / class decoratorRun handlers before the route handler — awaited, may reshape the request
@UseAfter(...handlers)method / class decoratorRun handlers after the response — detached, cannot alter it
EventHandlerinterface{ handle(ctx: ControllerContext): any }
ControllerContextinterfaceContext passed to @UseBefore / @UseAfter handlers
UseHandlertypeAn inline function or an injectable EventHandler class
IS_PUBLIC_KEYconstMetadata key used by @Public()
USE_BEFORE / USE_AFTERconstMetadata keys read by UseHooksInterceptor

Usage

cats.controller.ts
import { Controller, Get, Post, Patch, Param } from '@nestjs/common';
import { User, Public, ModifyBody, setCreatedBy } from '@nest-extended/decorators';
 
@Controller('cats')
export class CatsController {
  @Public()
  @Get()
  findAll() {
    // no JWT required
  }
 
  @Post()
  create(@ModifyBody(setCreatedBy()) body: CreateCatDto) {
    // body.createdBy === current user id
  }
 
  @Patch(':id')
  update(@Param('id') id: string, @ModifyBody(setCreatedBy('updatedBy')) body: UpdateCatDto) {
    // body.updatedBy === current user id
  }
 
  @Get('me')
  profile(@User() user: AuthenticatedUser) {
    return user;
  }
}

@ModifyBody accepts multiple modifier functions and runs them in order, so you can compose your own transforms alongside setCreatedBy.

@UseBefore / @UseAfter

New in 1.5.0. Run handlers around a route handler. Each handler is an inline function or an injectable class implementing EventHandler. Both decorators work on a single method or on a whole controller — class-level handlers run first.

cats.controller.ts
import { UseBefore, UseAfter, EventHandler, ControllerContext } from '@nest-extended/decorators';
 
@Injectable()
export class NotifyHandler implements EventHandler {
  constructor(private readonly mail: MailService) {}
  async handle(ctx: ControllerContext) { await this.mail.send(ctx.result); }
}
 
@Controller('cats')
@UseAfter(AuditHandler)                     // applies to every handler in the controller
export class CatsController {
  @Post()
  @UseBefore((ctx) => { ctx.body.slug = slugify(ctx.body.name); })
  @UseAfter(NotifyHandler, (ctx) => logger.log(ctx.result))
  create(@Body() dto: CreateCatDto) { /* ... */ }
}

The context each handler receives:

interface ControllerContext {
  request; response; user?;
  params; query; body;
  result?;              // @UseAfter only
  handler; controller;
}

@UseBefore is awaited and may mutate ctx.body / ctx.query. @UseAfter is detached — it cannot alter the response, and each handler runs independently so one failure does not stop the others. An injectable handler must be listed in the module's providers like any other.

These decorators are executed by UseHooksInterceptor in @nest-extended/core, which NestExtendedModule.forRoot() registers globally. For logic that should run for every caller — not just HTTP requests — use service events instead.

Next steps