first commit
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# `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.
|
||||
Reference in New Issue
Block a user