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
.
@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 :
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 :
@Field({ middleware: [checkRoleMiddleware] })@Extensions({ role: Role.ADMIN })password: string;