GraphQL API
Entrypoint:
pages/api/graphql.jsroutes to Yoga- Yoga handler:
lib/graphql/yogaHandler.tscreateYogawith schema, Sentry/plugin, parser cache,extraParamNames: ['id']for Relay- Context creation:
server/graphql/helpers/createResolversContext.js - Lightweight context (fast-path):
server/graphql/helpers/lightweightContext.ts
Schema:
- SDL files in
server/graphql/schema/*.graphql, merged byserver/graphql/schema/index.jsvia@graphql-tools/merge
Resolvers:
server/graphql/resolvers/index.jsis the entry pointserver/graphql/resolvers/**/*map fields/mutations/queries to services or Fauna- Many resolvers in JS/TS; newer services are in TS under
services/tenant/*andservices/global/*
Context:
- Auth & tenant resolution; feature flags; dataloaders; Fauna and Postgres clients
- Throws if required tokens missing depending on flags/postgres state
Lightweight context (fast-path for external API calls)
Some GraphQL queries are used as thin proxy calls to external APIs (e.g. Google Places) and do not need the full resolver context (flags, tenant resolution, DB verification, settings/plan loading, etc.).
To keep those requests fast, Yoga can bypass createResolversContext and instead return a minimal context:
- The switch is gated by
isLightweightQuery(params)inserver/graphql/helpers/lightweightContext.ts.
How the query is selected (safe by construction)
Lightweight context is used only when all of the following are true:
- The request is a query (mutations are always excluded).
- The request includes a Relay operation identifier in
params.id. params.idis explicitly allowlisted inLIGHTWEIGHT_QUERIES.- The request is still authenticated at the transport level (
isAuthenticated(request)), but we intentionally skip heavy “full context” initialization.
We intentionally check only the operation identifier (id) and do not inspect query text for field names/fragments. This avoids false positives where a larger query includes fragments that reference a “lightweight” resolver.
Adding a new lightweight query
- Ensure the query (and its resolvers) truly does not require full context fields (tenant, DB, flags, settings, plan, etc.).
- Add the Relay operation id to the allowlist in
server/graphql/helpers/lightweightContext.ts(LIGHTWEIGHT_QUERIES). - Keep resolvers compatible with minimal context:
- If a resolver needs full context, it should not be routed through the lightweight allowlist.
- If you branch on context, use
ctx.isLightweightto make the decision explicit.
Relay:
- Relay client/server environments under
lib/createEnvironment/* - Relay compiler config in
relay.config.js(Flow types, artifacts in__generated__)