Files
skills/docs/api-stack/api/api-graphql-yoga/src/guards/depth-and-complexity.md
2026-05-29 08:20:56 +01:00

68 lines
2.1 KiB
Markdown

# `depth-and-complexity.ts`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Implements the static depth + complexity guard that the Yoga engine runs
after parsing each query and before execution. Documents that exceed the
configured limits are rejected with `GRAPHQL_YOGA.DEPTH_EXCEEDED` or
`GRAPHQL_YOGA.COMPLEXITY_EXCEEDED`, which lets the host reject denial-of-
service payloads (deeply nested fragments, fan-out spreads) before any
resolver runs.
The guard is intentionally cheap: a single recursive walk over the
already-parsed `DocumentNode`, no schema awareness, no cost estimator.
Hosts that want a smarter cost model (database joins, external service
fan-out) compose a stricter guard on top.
## Features
- Tracks deepest `SelectionSet` nesting level per operation.
- Counts every `Field` node touched, expanding fragment spreads inline
once per occurrence.
- Throws subclass `GraphqlYogaError` with `context.depth` /
`context.limit` for log-side debugging.
## Usage: Basic
```ts
import { parse } from "graphql";
import { enforceGuards } from "@suaveplan/api-graphql-yoga";
const doc = parse("{ ping }");
enforceGuards(doc, { maxDepth: 10, maxComplexity: 1000 });
```
## Usage: Advanced
```ts
import { parse } from "graphql";
import { enforceGuards } from "@suaveplan/api-graphql-yoga";
const doc = parse(`
fragment f on Customer { id name orders { id } }
query { customer(id: "c1") { ...f } }
`);
try {
enforceGuards(doc, { maxDepth: 3, maxComplexity: 5 });
} catch (error) {
// GRAPHQL_YOGA.DEPTH_EXCEEDED or COMPLEXITY_EXCEEDED
}
```
## API Reference
- `enforceGuards(document, { maxDepth, maxComplexity })` — throws on
violation, returns `void` on pass.
## Implementation Notes
Fragment cycles would cause unbounded recursion if the walker re-visited
spreads; in practice the GraphQL `validate()` pass that runs immediately
after parsing rejects cycle-containing documents, so the depth/complexity
walker can rely on cycle-free input. Should a future change move the guard
ahead of validation, add a `Set<string>` of seen spreads to short-circuit.