NestJS Logo

Complexity

Warning This chapter applies only to the code first approach.

Query complexity lets you define how complex certain fields are, and restrict queries with a maximum complexity. The idea is to express the complexity of each field as a number. A common default is to give each field a complexity of 1. You can also customize how the complexity of a GraphQL query is calculated with complexity estimators. A complexity estimator is a function that calculates the complexity of a field. You can add any number of estimators to the rule, and they run one after another. The first estimator that returns a numeric value determines the complexity of that field.

The @nestjs/graphql package integrates with tools like graphql-query-complexity, which provides a solution based on cost analysis. With this library, you can reject queries that are too costly to execute.

Installation#

To begin, install the required dependency:


$ npm install --save graphql-query-complexity

Getting started#

Once the installation is complete, define the ComplexityPlugin class:


import { GraphQLSchemaHost } from '@nestjs/graphql';
import { Plugin } from '@nestjs/apollo';
import {
  ApolloServerPlugin,
  BaseContext,
  GraphQLRequestListener,
} from '@apollo/server';
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<BaseContext>> {
    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);
      },
    };
  }
}

For demonstration purposes, the maximum allowed complexity is set to 20. The example above uses two estimators, fieldExtensionsEstimator and simpleEstimator:

  • fieldExtensionsEstimator: extracts the complexity value defined for each field of your schema (through the field's extensions)
  • simpleEstimator: returns a fixed complexity for each field (used as the fallback for fields without a defined complexity)
Hint Remember to add this class to the providers array of a module.

Field-level complexity#

With this plugin in place, you can define the complexity of any field by specifying the complexity property in the options object passed to the @Field() decorator:


@Field({ complexity: 3 })
title: string;

Alternatively, you can define an estimator function:


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

Query/Mutation-level complexity#

The @Query() and @Mutation() decorators also accept a complexity property in their options object:


@Query(() => [Item], {
  complexity: (options: ComplexityEstimatorArgs) =>
    options.args.count * options.childComplexity,
})
items(@Args('count') count: number) {
  return this.itemsService.getItems({ count });
}
Edit on GitHub

Support us

Nest is an MIT-licensed open source project. It can grow thanks to the support of these awesome people. If you'd like to join them, please read more here.

Principal Sponsors

SerpApi LogoTrilon LogoMojam Logo

Sponsors / Partners

Become a sponsor