Passer au contenu

Complexité

La complexité des requêtes vous permet de définir à quel point certains champs sont complexes et de restreindre les requêtes avec une complexité maximale. L’idée est de définir à quel point chaque champ est complexe en utilisant un simple nombre. Un défaut commun est d’attribuer à chaque champ une complexité de 1. De plus, le calcul de la complexité d’une requête GraphQL peut être personnalisé avec ce qu’on appelle des estimateurs de complexité. Un estimateur de complexité est une simple fonction qui calcule la complexité pour un champ. Vous pouvez ajouter autant d’estimateurs de complexité que vous le souhaitez à la règle, qui seront ensuite exécutés les uns après les autres. Le premier estimateur qui retourne une valeur de complexité numérique détermine la complexité pour ce champ.

Le paquet @nestjs/graphql s’intègre très bien avec des outils comme graphql-query-complexity qui fournissent une solution basée sur l’analyse des coûts. Avec cette bibliothèque, vous pouvez rejeter des requêtes à votre serveur GraphQL jugées trop coûteuses à exécuter.

Installation

Pour commencer à l’utiliser, nous devons d’abord installer la dépendance requise.

Fenêtre de terminal
$ npm install --save graphql-query-complexity

Premiers pas

Une fois le processus d’installation terminé, nous pouvons définir la classe ComplexityPlugin :

ComplexityPlugin
import { GraphQLSchemaHost } from "@nestjs/graphql";
import { Plugin } from "@nestjs/apollo";
import {
ApolloServerPlugin,
GraphQLRequestListener,
} from 'apollo-server-plugin-base';
import { GraphQLError } from 'graphql';
import {
fieldExtensionsEstimator,
getComplexity,
simpleEstimator,
} from 'graphql-query-complexity';
@Plugin()
export class ComplexityPlugin implements ApolloServerPlugin {
constructor(private gqlSchemaHost: GraphQLSchemaHost) {}
async requestDidStart(): Promise<GraphQLRequestListener> {
const maxComplexity = 20;
const { schema } = this.gqlSchemaHost;
return {
async didResolveOperation({ request, document }) {
const complexity = getComplexity({
schema,
operationName: request.operationName,
query: document,
variables: request.variables,
estimators: [
fieldExtensionsEstimator(),
simpleEstimator({ defaultComplexity: 1 }),
],
});
if (complexity > maxComplexity) {
throw new GraphQLError(
`Query is too complex: ${complexity}. Maximum allowed complexity: ${maxComplexity}`,
);
}
console.log('Query Complexity:', complexity);
},
};
}
}

À des fins de démonstration, nous avons spécifié la complexité maximale autorisée à 20. Dans l’exemple ci-dessus, nous avons utilisé 2 estimateurs : le simpleEstimator et le fieldExtensionsEstimator.

  • simpleEstimator : l’estimateur simple renvoie une complexité fixe pour chaque champ.
  • fieldExtensionsEstimator : l’estimateur des extensions de champ extrait la valeur de complexité pour chaque champ de votre schéma.

Complexité au niveau du champ

Avec ce plugin en place, nous pouvons désormais définir la complexité pour n’importe quel champ en spécifiant la propriété complexity dans l’objet d’options passé au décorateur @Field(), comme suit :

Complexity au niveau du champ
@Field({ complexity: 3 })
title: string;

Alternativement, vous pouvez définir la fonction d’estimation :

Estimateur de Complexité
@Field({
complexity: (options: ComplexityEstimatorArgs) => ...
})
title: string;

Complexité au niveau des requêtes et mutations

De plus, les décorateurs @Query() et @Mutation() peuvent avoir une propriété complexity spécifiée comme suit :

Complexité au niveau des requêtes
@Query({
complexity: (options: ComplexityEstimatorArgs) => options.args.count * options.childComplexity
})
items(@Args('count') count: number) {
return this.itemsService.getItems({ count });
}