Décorateurs de route personnalisés
Nest est construit autour d’une fonctionnalité de langage appelée décorateurs. Les décorateurs sont un concept bien connu dans de nombreux langages de programmation couramment utilisés, mais dans le monde de JavaScript, ils sont encore relativement nouveaux. Pour mieux comprendre comment fonctionnent les décorateurs, nous vous recommandons de lire cet article. Voici une définition simple :
Un décorateur ES2016 est une expression qui renvoie une fonction et peut prendre un objectif, un nom et un descripteur de propriété comme arguments. Vous l’appliquez en préfixant le décorateur avec un caractère
@
et en le plaçant au tout début de ce que vous essayez de décorer. Les décorateurs peuvent être définis pour une classe, une méthode ou une propriété.
Paramètres de décorateurs
Nest fournit un ensemble de décorateurs de paramètres utiles que vous pouvez utiliser avec les gestionnaires de routes HTTP. Voici une liste des décorateurs fournis et des objets Express (ou Fastify) plain qu’ils représentent :
Décorateur | Objet Express |
---|---|
@Request(), @Req() | req |
@Response(), @Res() | res |
@Next() | next |
@Session() | req.session |
@Param(param?: string) | req.params / req.params[param] |
@Body(param?: string) | req.body / req.body[param] |
@Query(param?: string) | req.query / req.query[param] |
@Headers(param?: string) | req.headers / req.headers[param] |
@Ip() | req.ip |
@HostParam() | req.hosts |
De plus, vous pouvez créer vos propres décorateurs personnalisés. Pourquoi est-ce utile ?
Dans le monde Node.js, il est courant d’attacher des propriétés à l’objet request. Ensuite, vous les extrayez manuellement dans chaque gestionnaire de route, en utilisant du code comme suit :
const user = req.user;
Pour rendre votre code plus lisible et transparent, vous pouvez créer un décorateur @User()
et le réutiliser dans tous vos contrôleurs.
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator( (data: unknown, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return request.user; },);
Ensuite, vous pouvez simplement l’utiliser là où cela correspond à vos besoins.
@Get()async findOne(@User() user: UserEntity) { console.log(user);}
Transmettre des données
Lorsque le comportement de votre décorateur dépend de certaines conditions, vous pouvez utiliser le paramètre data
pour passer un argument à la fonction de fabrique du décorateur. Un cas d’utilisation pour cela est un décorateur personnalisé qui extrait des propriétés de l’objet request par clé. Supposons par exemple que notre couche d’authentification valide les requêtes et attache une entité utilisateur à l’objet request. L’entité utilisateur pour une requête authentifiée pourrait ressembler à ceci :
{ "id": 101, "firstName": "Alan", "lastName": "Turing", "roles": ["admin"]}
Définissons un décorateur qui prend un nom de propriété comme clé et renvoie la valeur associée si elle existe (ou undefined si elle n’existe pas, ou si l’objet user
n’a pas été créé).
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator( (data: string, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); const user = request.user;
return data ? user?.[data] : user; },);
Voici comment vous pourriez alors accéder à une propriété particulière via le décorateur @User()
dans le contrôleur :
@Get()async findOne(@User('firstName') firstName: string) { console.log(`Hello ${firstName}`);}
Vous pouvez utiliser ce même décorateur avec différentes clés pour accéder à différentes propriétés. Si l’objet user
est profond ou complexe, cela peut faciliter la mise en œuvre des gestionnaires de requêtes et les rendre plus lisibles.
Travailler avec des pipes
Nest traite les décorateurs de paramètres personnalisés de la même manière que les décorateurs intégrés (@Body()
, @Param()
et @Query()
). Cela signifie que les pipes sont exécutés pour les paramètres annotés personnalisés aussi (dans nos exemples, l’argument user
). De plus, vous pouvez appliquer le pipe directement au décorateur personnalisé :
@Get()async findOne( @User(new ValidationPipe({ validateCustomDecorators: true, })) user: UserEntity,) { console.log(user);}
Composition de décorateurs
Nest fournit une méthode d’aide pour composer plusieurs décorateurs. Par exemple, supposons que vous souhaitiez combiner tous les décorateurs liés à l’authentification en un seul décorateur. Cela pourrait être fait avec la construction suivante :
import { applyDecorators } from '@nestjs/common';
export function Auth(...roles: Role[]) { return applyDecorators( SetMetadata('roles', roles), UseGuards(AuthGuard, RolesGuard), ApiBearerAuth(), ApiUnauthorizedResponse({ description: 'Unauthorized' }), );}
Vous pouvez ensuite utiliser ce décorateur @Auth()
personnalisé comme suit :
@Get('users')@Auth('admin')findAllUsers() {}
Cela a pour effet d’appliquer les quatre décorateurs avec une seule déclaration.