Passer au contenu

Extensions

Les extensions sont une fonctionnalité avancée et de bas niveau qui vous permet de définir des données arbitraires dans la configuration des types. Attacher des métadonnées personnalisées à certains champs vous permet de créer des solutions plus sophistiquées et génériques. Par exemple, avec les extensions, vous pouvez définir des rôles requis au niveau du champ pour accéder à des champs particuliers. De tels rôles peuvent être reflétés à l’exécution pour déterminer si l’appelant a les autorisations suffisantes pour récupérer un champ spécifique.

Ajouter des métadonnées personnalisées

Pour attacher des métadonnées personnalisées pour un champ, utilisez le décorateur @Extensions() exporté du paquet @nestjs/graphql.

Ajouter des métadonnées personnalisées
@Field()
@Extensions({ role: Role.ADMIN })
password: string;

Dans l’exemple ci-dessus, nous avons attribué à la propriété de métadonnées role la valeur de Role.ADMIN. Role est un simple énumérateur TypeScript qui regroupe tous les rôles d’utilisateur disponibles dans notre système.

Notez qu’en plus de définir des métadonnées sur les champs, vous pouvez également utiliser le décorateur @Extensions() au niveau de la classe et du niveau de méthode (par exemple, sur le gestionnaire de requêtes).

Utiliser des métadonnées personnalisées

La logique qui exploite les métadonnées personnalisées peut être aussi complexe que nécessaire. Par exemple, vous pouvez créer un simple intercepteur qui stocke/journalise les événements par invocation de méthode, ou un middleware de champ qui fait correspondre les rôles requis pour récupérer un champ avec les autorisations de l’appelant (système de permissions au niveau du champ).

Pour illustrer, définissons un checkRoleMiddleware qui compare le rôle d’un utilisateur (codé en dur ici) avec un rôle requis pour accéder à un champ cible :

Middleware de vérification de rôle
export const checkRoleMiddleware: FieldMiddleware = async (
ctx: MiddlewareContext,
next: NextFn,
) => {
const { info } = ctx;
const { extensions } = info.parentType.getFields()[info.fieldName];
/**
* Dans une application réelle, la variable "userRole"
* devrait représenter le rôle de l'appelant (utilisateur) (par exemple, "ctx.user.role").
*/
const userRole = Role.USER;
if (userRole === extensions.role) {
throw new ForbiddenException(
`L'utilisateur n'a pas les autorisations suffisantes pour accéder au champ "${info.fieldName}".`,
);
}
return next();
};

Avec cela en place, nous pouvons enregistrer un middleware pour le champ password, comme suit :

Enregistrer le middleware pour le champ password
@Field({ middleware: [checkRoleMiddleware] })
@Extensions({ role: Role.ADMIN })
password: string;