Contexte d’exécution
Nest fournit plusieurs classes utilitaires qui facilitent l’écriture d’applications fonctionnant dans plusieurs contextes (par exemple, serveurs HTTP basés sur Nest, microservices et contextes d’application WebSockets). Ces utilitaires fournissent des informations sur le contexte d’exécution actuel, qui peuvent être utilisées pour construire des gardes, des filtres et des intercepteurs génériques qui peuvent fonctionner sur un large éventail de contrôleurs, de méthodes et de contextes d’exécution.
Nous couvrons deux de ces classes dans ce chapitre : ArgumentsHost
et ExecutionContext
.
Classe ArgumentsHost
La classe ArgumentsHost
fournit des méthodes pour récupérer les arguments passés à un gestionnaire. Elle permet de choisir le contexte approprié (par exemple, HTTP, RPC (microservice), ou WebSockets) pour récupérer les arguments. Le framework fournit une instance de ArgumentsHost
, généralement référencée comme un paramètre host
, dans les cas où vous souhaitez y accéder. Par exemple, la méthode catch()
d’un filtre d’exception est appelée avec une instance ArgumentsHost
.
ArgumentsHost
agit simplement comme une abstraction sur les arguments d’un gestionnaire. Par exemple, pour les applications de serveur HTTP (lorsque @nestjs/platform-express
est utilisé), l’objet host
encapsule le tableau [request, response, next]
, où request
est l’objet de requête, response
est l’objet de réponse et next
est une fonction qui contrôle le cycle de requête-réponse de l’application. D’autre part, pour les applications GraphQL, l’objet host
contient le tableau [root, args, context, info]
.
Contexte d’application actuel
Lors de la création de gardes, de filtres et d’intercepteurs génériques qui doivent fonctionner dans plusieurs contextes d’application, nous avons besoin d’un moyen pour déterminer le type d’application dans lequel notre méthode s’exécute actuellement. Faites cela avec la méthode getType()
d’ArgumentsHost
:
if (host.getType() === 'http') { // faites quelque chose qui est seulement important dans le contexte des requêtes HTTP normales (REST)} else if (host.getType() === 'rpc') { // faites quelque chose qui est seulement important dans le contexte des requêtes Microservice} else if (host.getType<GqlContextType>() === 'graphql') { // faites quelque chose qui est seulement important dans le contexte des requêtes GraphQL}
Avec le type d’application disponible, nous pouvons écrire des composants plus génériques, comme illustré ci-dessous.
Arguments des gestionnaires d’hôte
Pour récupérer le tableau des arguments passés au gestionnaire, une approche consiste à utiliser la méthode getArgs()
de l’objet host
.
const [req, res, next] = host.getArgs();
Vous pouvez extraire un argument particulier par index en utilisant la méthode getArgByIndex()
:
const request = host.getArgByIndex(0);const response = host.getArgByIndex(1);
Dans ces exemples, nous avons récupéré les objets de requête et de réponse par index, ce qui n’est généralement pas recommandé car cela lie l’application à un contexte d’exécution particulier. Au lieu de cela, vous pouvez rendre votre code plus robuste et réutilisable en utilisant l’une des méthodes utilitaires de l’objet host
pour passer au contexte d’application approprié pour votre application. Les méthodes utilitaires de changement de contexte sont indiquées ci-dessous.
/** * Changer le contexte en RPC. */ switchToRpc(): RpcArgumentsHost;
/** * Changer le contexte en HTTP. */ switchToHttp(): HttpArgumentsHost;
/** * Changer le contexte en WebSockets. */ switchToWs(): WsArgumentsHost;
Réécrivons l’exemple précédent en utilisant la méthode switchToHttp()
. L’appel d’aide host.switchToHttp()
renvoie un objet HttpArgumentsHost
approprié pour le contexte d’application HTTP. L’objet HttpArgumentsHost
possède deux méthodes utiles que nous pouvons utiliser pour extraire les objets souhaités. Nous utilisons également les assertions de type Express dans ce cas pour retourner des objets typés natifs Express :
const ctx = host.switchToHttp();const request = ctx.getRequest<Request>();const response = ctx.getResponse<Response>();
De même, WsArgumentsHost
et RpcArgumentsHost
ont des méthodes pour retourner des objets appropriés dans les contextes de microservices et de WebSockets. Voici les méthodes pour WsArgumentsHost
:
export interface WsArgumentsHost { /** * Retourne l'objet de données. */ getData<T>(): T;
/** * Retourne l'objet client. */ getClient<T>(): T;}
Voici les méthodes pour RpcArgumentsHost
:
export interface RpcArgumentsHost { /** * Retourne l'objet de données. */ getData<T>(): T;
/** * Retourne l'objet de contexte. */ getContext<T>(): T;}
Classe ExecutionContext
ExecutionContext
étend ArgumentsHost
, fournissant des détails supplémentaires sur le processus d’exécution actuel. Comme ArgumentsHost
, Nest fournit une instance de ExecutionContext
dans les endroits où vous pourriez en avoir besoin, comme dans la méthode canActivate()
d’un garde et la méthode intercept()
d’un intercepteur. Il fournit les méthodes suivantes :
export interface ExecutionContext extends ArgumentsHost { /** * Retourne le type de la classe du contrôleur à laquelle appartient le gestionnaire actuel. */ getClass<T>(): Type<T>;
/** * Retourne une référence au gestionnaire (méthode) qui sera invoqué ensuite dans le * pipeline de requêtes. */ getHandler(): Function;}
La méthode getHandler()
renvoie une référence au gestionnaire qui va être invoqué. La méthode getClass()
renvoie le type de la classe Controller
à laquelle appartient ce gestionnaire particulier. Par exemple, dans un contexte HTTP, si la requête actuellement traitée est une requête POST
, liée à la méthode create()
sur le CatsController
, getHandler()
renvoie une référence à la méthode create()
et getClass()
renvoie la classe CatsController
(pas l’instance).
const methodKey = ctx.getHandler().name; // "create"const className = ctx.getClass().name; // "CatsController"
La capacité d’accéder à des références à la fois à la classe actuelle et à la méthode gestionnaire offre une grande flexibilité. Plus important encore, cela nous donne l’occasion d’accéder aux métadonnées définies via des décorateurs créés via Reflector#createDecorator
ou le décorateur intégré @SetMetadata()
depuis les gardes ou les intercepteurs. Nous couvrons ce cas d’utilisation ci-dessous.