Query Depth
- A defense mechanism against unbounded deeply nested GraphQL queries.
- We need to limit the total depth of each operation.
- My current implementation in
apps/complexity+ComplexityPluginis doing just that but it lacks taking into account the Connection pagination (learn more here). - Deciding when a GraphQL query is “too complex” is a nuanced and subtle art.
@escape.tech/graphql-armor
[!NOTE]
At first I thought to use
graphql-depth-limit-ts, but then I found@escape.tech/graphql-armor. It offers features provided bygraphql-query-complexityandgraphql-depth-limit-ts. So I am down :joy:.
I am gonna try this lib with type-graphql. The e2e tests + app: apps/depth and apps/depth-e2e.
-
pnpm install graphql type-graphql reflect-metadata typeorm pg @escape.tech/graphql-armor -
nx g @nx/node:app apps/depth --framework express --bundler esbuild - Configure your TypeORM and
type-graphqlbackend. - Configure your
@escape.tech/graphql-armorwith your Apollo Server (learn more).
For example this query with that config will work:
| GraphQL Query | Config |
|---|---|
| ```graphql query { businesses { edges { cursor node { id name customers { id shopAt { id customers { id } } } } } } } ``` | ```ts new ApolloArmor({ maxDepth: { enabled: true, ignoreIntrospection: true, n: 7, flattenFragments: true, }, costLimit: { enabled: true, depthCostFactor: 1.5, objectCost: 2, scalarCost: 1, ignoreIntrospection: true, flattenFragments: true, maxCost: 100, }, }); ``` |
-
We have 7 as the maximum level of nestedness. That corresponds to the
n: 7in ourmaxDepth.
-
After that we can take a look at how it is calculating our GraphQL query’s cost, we have said
depthCostFactorshould be 1.5,objectCostshould be 2, and finallyscalarCostis 1. Let’s first break down our queryCost calculation formula:
objectCost+ (child complexity *depthCostFactor). You can see how I know that this lib at the time of writing this doc is using this formula here.Depth Field Type Base Cost Child Cost * Depth Factor Total Cost 0 queryObject n/a n/a n/a 1 businessesObject 2 7 * 1.5 12.5 2 edgesObject 2 6 * 1.5 11 3 cursor,nodeScalar + Object 1 + 2 9 * 1.5 16.5 4 id,name,customersScalar + Scalar + Object 1 + 1 + 2 6 * 1.5 13 5 id,shopAtScalar + Object 1 + 2 3 * 1.5 7.5 6 id,customersScalar + Object 1 + 2 1 * 1.5 4.5 7 idScalar 1 0 1 Cost Of Executing This Query 66