Passer au contenu

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 :

Exemple de détermination du type d'application
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.

Récupération des arguments
const [req, res, next] = host.getArgs();

Vous pouvez extraire un argument particulier par index en utilisant la méthode getArgByIndex() :

Extraction d'arguments par index
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.

Méthodes de changement de contexte
/**
* 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 :

Utilisation de switchToHttp
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 :

Interface 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 :

Interface 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 :

Interface ExecutionContext
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).

Exemple d'accès au gestionnaire
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.