Files
suaveplan/packages/api-stack/api/api-graphql-yoga/README.md
2026-05-27 23:29:53 +01:00

6.7 KiB

@suaveplan/api-graphql-yoga — GraphQL Yoga engine adapter for @suaveplan/api-graphql. Default GraphQL engine per design doc §10.5. Implements the abstract GraphqlEngine contract from @suaveplan/api-graphql via createYogaGraphqlEngine(opts) — Zod-validated YogaGraphqlOptions, federation through @graphql-tools/schema makeExecutableSchema, schema-collision detection delegated to the canonical GRAPHQL.SCHEMA_COLLISION code, per-request DataLoader scoping bound to RequestContext, depth + complexity guards, masked errors / introspection toggles, graphql-ws subscription transport over an injected api-ws broker, OTel instruments (requests counter, request duration histogram, resolver duration histogram, subscriptions_active gauge, schema_rebuilds counter), 10 GRAPHQL_YOGA_* error codes, and a ./testing subpath re-exporting runGraphqlEngineConformance bound to the Yoga factory.

Stage-7 GraphQL Yoga engine adapter. Default GraphQL engine for the Suaveplan API plugin system per design doc §10.5 — Bun-friendly, fastest for our usage pattern, and simpler to operate than Apollo Server. Implements the abstract GraphqlEngine contract from @suaveplan/api-graphql so the same conformance suite (runGraphqlEngineConformance) passes against this adapter and any future engine; swapping engines is host-config-only.

Documentation tree

  • execute-helpers — Houses the smaller execution helpers the Yoga engine uses on every request, kept out of yoga-engine.ts so the orchest…
  • yoga-engine — Implements the abstract GraphqlEngine contract from @suaveplan/api-graphql over the Yoga / graphql-js stack. The…
  • error-codes — Defines the frozen GRAPHQL_YOGA.* error-code registry and the GraphqlYogaError subclass of SuaveplanError used th…
    • error-codes — Defines the frozen GRAPHQL_YOGA.* error-code registry and the GraphqlYogaError subclass of SuaveplanError used th…
  • federation — Aggregates plugin-side GraphqlRegistry contributions into a single (MergedSchema, ResolverMap) pair that the Yoga e…
    • federation — Aggregates plugin-side GraphqlRegistry contributions into a single (MergedSchema, ResolverMap) pair that the Yoga e…
  • guards — Implements the static depth + complexity guard that the Yoga engine runs after parsing each query and before execution.…
    • depth-and-complexity — Implements the static depth + complexity guard that the Yoga engine runs after parsing each query and before execution.…
  • instruments — Builds and caches the OpenTelemetry instrument bundle the Yoga GraphQL engine emits per request. The bundle covers a co…
    • instruments — Builds and caches the OpenTelemetry instrument bundle the Yoga GraphQL engine emits per request. The bundle covers a co…
  • loaders — Defines the per-request loader bag the Yoga engine constructs at pipeline step 7 and disposes at step 11. Two concurren…
    • loaders — Defines the per-request loader bag the Yoga engine constructs at pipeline step 7 and disposes at step 11. Two concurren…
  • options — Defines YogaGraphqlOptions, the Zod-validated configuration boundary that hosts use to wire createYogaGraphqlEngine…
    • options — Defines YogaGraphqlOptions, the Zod-validated configuration boundary that hosts use to wire createYogaGraphqlEngine…
  • subscriptions — Bridges the WsBroker contract from @suaveplan/api-ws to GraphQL Subscription resolvers via `AsyncIterable<Payload…
    • subscriptions — Bridges the WsBroker contract from @suaveplan/api-ws to GraphQL Subscription resolvers via `AsyncIterable<Payload…
  • testing — Binds the abstract runGraphqlEngineConformance from @suaveplan/api-graphql/testing to the Yoga engine factory so co…
    • testing — Binds the abstract runGraphqlEngineConformance from @suaveplan/api-graphql/testing to the Yoga engine factory so co…

Modules

  • engine — createYogaGraphqlEngine(config) + helpers (maskOrPassthrough, withTimeout, assertIntrospectionAllowed, wrapSubscription).
  • federation — federatePlugins(entries) aggregating multiple plugin contributions into one (MergedSchema, ResolverMap) pair via mergeSdl from @suaveplan/api-graphql.
  • options — Zod-validated YogaGraphqlOptions + resolveYogaGraphqlOptions with safe defaults (endpoint: "/graphql", maxQueryDepth: 10, maxQueryComplexity: 1000, timeoutMs: 30000, maskedErrors: true).
  • guards — enforceGuards(doc, { maxDepth, maxComplexity }) static depth + complexity rejection.
  • loaders — buildRequestLoaders(factories) per-request DataLoader bag bound to RequestContext.
  • subscriptions — subscribeBrokerTopic(broker, topic, tenant) bridges api-ws to GraphQL AsyncIterable.
  • instruments — getYogaInstruments() OTel counter / histogram / gauge bundle.
  • error-codes — 10 GRAPHQL_YOGA.* codes + GraphqlYogaError.
  • testing — runYogaConformance(label?, config?) bound conformance harness.

Quick start

import { createGraphqlRegistry } from "@suaveplan/api-graphql";
import { createYogaGraphqlEngine } from "@suaveplan/api-graphql-yoga";

const engine = createYogaGraphqlEngine();
const reg = createGraphqlRegistry();
reg.addTypes("type Query { ping: String! }");
reg.addResolvers({ Query: { ping: () => "pong" } });
engine.buildSchema(reg);
const result = await engine.executeQuery({ query: "{ ping }" }, ctx);

Why this engine?

  • Bun runtime parity — graphql-yoga is a thin layer over graphql-js and runs natively under Bun without polyfills.
  • WebSocket subscriptions over api-ws — graphql-ws protocol bridged to the WS broker via subscribeBrokerTopic.
  • Per-request DataLoader scoping — design doc §10.3 mandates per-request DataLoader instances; the buildRequestLoaders helper enforces this at the engine boundary.
  • Depth + complexity guards — denial-of-service rejection before resolvers run.
  • Masked error mode — flips production error messages to "Unexpected error." while preserving the path for log-side debugging.

License

MIT — Suaveplan Team.