Patterns de décorateurs NestJS

VérifiéSûr

Guide des décorateurs NestJS intégrés et personnalisés : routes, paramètres, métadonnées et composition. Couvre createParamDecorator et Reflector.

Spar Skills Guide Bot
DeveloppementIntermédiaire
01/11/2026
Claude CodeCursorWindsurfCopilotCodex
#nestjs#decorators#typescript#backend#metadata

Recommandé pour

Synthèse automatique

Guide l’utilisation des décorateurs NestJS natifs et personnalisés, leur composition et la réflexion de métadonnées pour les contrôleurs, guards et intercepteurs.

Points forts

  • Couvre les décorateurs de classe, de route et de paramètres avec des exemples concis.
  • Explique la composition des décorateurs et la création de décorateurs de paramètres personnalisés via createParamDecorator et SetMetadata.
  • Rappelle la configuration tsconfig nécessaire et le risque lié à l’injection de @Res().
  • Délimite clairement le périmètre par rapport aux skills NestJS connexes.

Limites

  • Le contenu semble tronqué au milieu de la section sur @Res().
  • Les exemples de décorateurs personnalisés et d’utilisation de Reflector ne sont pas fournis en entier.
  • Se limite à NestJS et exclut volontairement les modules/DI généraux, GraphQL et les décorateurs d’entités ORM.
Quand l'utiliser

À utiliser lors de l’écriture ou de la revue de contrôleurs, guards, intercepteurs ou décorateurs personnalisés NestJS reposant sur les paramètres de route et les métadonnées.

Quand l'éviter

À ne pas utiliser pour la conception générale des modules/DI NestJS, les décorateurs GraphQL, les décorateurs d’entités ORM ou les frameworks non NestJS.

Analyse de sécurité

Sûr
Score qualité90/100

Pure reference documentation for NestJS decorators. It contains only TypeScript snippets illustrating framework APIs (controllers, param decorators, guards, metadata reflection) and never instructs the agent to execute shell commands, touch the network, modify files, or handle secrets. No prompt-injection or instruction-override attempts were present in the content.

Aucun point d'attention détecté

Comment cette analyse est faite

Exemples

Custom current-user decorator
Create a @CurrentUser() param decorator in NestJS that extracts the authenticated user from the request, and show how to use it in a controller method.
Role metadata with Reflector
Show me how to use SetMetadata and Reflector in a NestJS guard to implement role-based access control on controller routes.
Compose guards and interceptors
How do I compose @UseGuards and @UseInterceptors on a NestJS controller while keeping the decorator order and behavior clear?

name: decorator-patterns description: | NestJS decorator usage: built-in route/param/class decorators, custom decorators via createParamDecorator and SetMetadata, metadata reflection via Reflector. Apply when designing controllers, guards, interceptors, or custom decorators.

Use this skill to:

  • Pick the right built-in decorator for routes, params, and DI.
  • Compose decorators (@UseGuards(A, B) @UseInterceptors(C)).
  • Build custom param decorators (e.g., @CurrentUser()).
  • Use metadata for role-based logic (Reflector + SetMetadata).
  • Avoid common decorator mistakes.

Do NOT use this skill for:

  • General module/DI patterns (see nest-conventions).
  • GraphQL-specific decorators (see nest-advanced).
  • ORM entity decorators (see nest-data-layer). user-invocable: false paths: ["src/**/*.ts"]

NestJS Decorator Patterns

NestJS is decorator-driven. Knowing which decorator does what — and how they compose — prevents most "weird DI / weird routing" bugs.

Required tsconfig

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

emitDecoratorMetadata is what makes runtime introspection (and class-validator/class-transformer) work. Never disable.

reflect-metadata polyfill must be imported once at the top of main.ts:

import 'reflect-metadata';

(NestJS does this implicitly via @nestjs/core, but if you write a script that uses decorators outside the Nest app, import it manually.)

Class-level decorators

@Controller(prefix)

@Controller('users')                            // routes prefixed /users
@Controller({ path: 'users', version: '1' })    // versioned: /v1/users (with VersioningType.URI)
export class UsersController {}

@Injectable(options?)

@Injectable()                                   // singleton (default)
@Injectable({ scope: Scope.REQUEST })           // per-request
export class MyService {}

@Module(...)

@Module({ imports, controllers, providers, exports })
export class UsersModule {}

@Global()

@Global()
@Module({ providers: [...], exports: [...] })
export class LoggerModule {}

Use sparingly — see nest-conventions.

Method-level: HTTP routing

@Get()                          // GET /users
@Get(':id')                     // GET /users/:id
@Post()
@Put(':id')
@Patch(':id')
@Delete(':id')
@All('debug')                   // any method
@Head()
@Options()

Route options

@HttpCode(204)                  // override default status (200/201)
@Header('Cache-Control', 'no-store')
@Redirect('https://example.com', 301)
@Render('user-profile')         // for view engines (rare in API-only)

Versioning

@Controller({ path: 'users', version: ['1', '2'] })
@Version('2')                   // override at method level
@Get()
findV2() {}

Param decorators

@Get(':id')
async findOne(
  @Param('id') id: string,                          // route param
  @Query('include') include: string,                // ?include=...
  @Headers('authorization') authHeader: string,     // single header
  @Headers() allHeaders: Record<string, string>,    // all headers
  @Body() dto: UpdateUserDto,                       // request body (validated by ValidationPipe)
  @Body('email') email: string,                     // single field (no DTO validation — avoid)
  @Req() req: Request,                              // raw request (escape hatch)
  @Res() res: Response,                             // raw response (rare; breaks NestJS lifecycle)
  @Ip() ip: string,
  @HostParam() hosts: Record<string, string>,
  @Session() session: Record<string, unknown>,      // requires session middleware
) {}

@Res() warning

When you inject @Res() and call res.send() directly, NestJS skips its response-handling pipeline (interceptors, exception filters that produce a response). Either:

  • Don't inject @Res() — return data and let Nest handle the response.
  • Or inject @Res({ passthrough: true }) and still return data.
@Get()
async getStream(@Res({ passthrough: true }) res: Response): Promise<StreamableFile> {
  res.set({ 'Content-Type': 'application/octet-stream' });
  return new StreamableFile(buffer);
}

Pipe binding

@Get(':id')
findOne(
  @Param('id', ParseIntPipe) id: number,                    // built-in pipe
  @Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number,
  @Body(new ValidationPipe({ whitelist: true })) dto: CreateUserDto,
) {}

Pipes run in order, left-to-right. Combine for type-safe + validated input.

Guard / Interceptor / Filter binding

@UseGuards(JwtAuthGuard, RolesGuard)
@UseInterceptors(LoggingInterceptor, CacheInterceptor)
@UseFilters(AllExceptionsFilter)
@UsePipes(new ValidationPipe({ transform: true }))
@Controller('users')
export class UsersController {}

Apply at route level OR globally:

// global guard via DI (preferred — can inject deps)
@Module({
  providers: [
    { provide: APP_GUARD, useClass: JwtAuthGuard },
    { provide: APP_INTERCEPTOR, useClass: LoggingInterceptor },
    { provide: APP_FILTER, useClass: AllExceptionsFilter },
    { provide: APP_PIPE, useClass: ValidationPipe },
  ],
})

// or in main.ts (cannot inject DI)
app.useGlobalGuards(new JwtAuthGuard());

APP_GUARD etc. are imported from @nestjs/core constants.

Metadata via SetMetadata + Reflector

For role-based or feature-flag logic, attach metadata to a route, then read in a guard.

Define a metadata decorator

// src/auth/roles.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const ROLES_KEY = 'roles';
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);

Apply on route

@Controller('admin')
@UseGuards(JwtAuthGuard, RolesGuard)
export class AdminController {
  @Get('users')
  @Roles('admin', 'super-admin')
  listUsers() { ... }
}

Read in guard

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const required = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (!required) return true;
    const { user } = context.switchToHttp().getRequest();
    return required.some(r => user.roles?.includes(r));
  }
}

getAllAndOverride walks handler → class metadata; method-level wins. getAllAndMerge combines both.

Custom param decorator

// src/auth/current-user.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const CurrentUser = createParamDecorator(
  (data: keyof User | undefined, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const user = request.user as User;
    return data ? user?.[data] : user;
  },
);

Usage:

@Get('me')
me(@CurrentUser() user: User) {}

@Get('email')
myEmail(@CurrentUser('email') email: string) {}

Works in HTTP, GraphQL, WebSocket contexts via switchToHttp / switchToWs / GraphQL execution context wrapper.

Composing decorators

For a frequently-used combo, build a meta-decorator with applyDecorators:

// src/auth/auth.decorator.ts
import { applyDecorators, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiUnauthorizedResponse } from '@nestjs/swagger';

export function Auth(...roles: string[]) {
  return applyDecorators(
    UseGuards(JwtAuthGuard, RolesGuard),
    Roles(...roles),
    ApiBearerAuth(),
    ApiUnauthorizedResponse({ description: 'unauthorized' }),
  );
}

Usage:

@Auth('admin')
@Get('users')
listUsers() { ... }

Reduces decorator stack noise when 4+ decorators repeat.

Anti-patterns

  • ❌ Using Reflect.getMetadata(...) directly — use Reflector.get() (NestJS API). It handles inheritance correctly.
  • ❌ @Body('field') instead of a typed DTO — bypasses class-validator, no type safety.
  • ❌ Injecting @Res() then forgetting passthrough: true — breaks interceptors.
  • ❌ Multiple class-level @UseGuards(A) @UseGuards(B) — last one wins; combine into one: @UseGuards(A, B).
  • ❌ Custom decorator without preserving type info — declare return type explicitly.
  • ❌ SetMetadata('key', val) inline at the route — make a named decorator (Roles(...)) so it's discoverable.
  • ❌ @Controller('/users/') — no leading or trailing slash; Nest adds them.

Du fichier au premier essai

Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.

Consulter la source et ses fichiers annexes

Ce téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.

1. Télécharger le fichier

Télécharger SKILL.md

Depuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.

Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.

mkdir -p '.skill-downloads/nestjs-decorator-patterns-mvda897w' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/nestjs-decorator-patterns-mvda897w/download' --output '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md.part' && mv '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md.part' '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md'

2. Vérifier les prérequis

Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.

Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.

Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.

3. Charger la skill

Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.

Claude Code
test -f '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md' && test -s '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/decorator-patterns' && cp -R '.skill-downloads/nestjs-decorator-patterns-mvda897w' '.claude/skills/decorator-patterns'

Cursor
test -f '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md' && test -s '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/decorator-patterns' && cp -R '.skill-downloads/nestjs-decorator-patterns-mvda897w' '.cursor/skills/decorator-patterns'

Codex
test -f '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md' && test -s '.skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/decorator-patterns' && cp -R '.skill-downloads/nestjs-decorator-patterns-mvda897w' '.agents/skills/decorator-patterns'

OpenSkills

OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.

Installation officielle d’OpenSkills
openskills install './.skill-downloads/nestjs-decorator-patterns-mvda897w'

openskills read 'nestjs-decorator-patterns-mvda897w'

La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.

Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.

openskills sync

Mode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.

4. Faire un premier essai

Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :

Lis .skill-downloads/nestjs-decorator-patterns-mvda897w/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.

Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.

Skills similaires