Skip to content

GraphQL API

Entrypoint:

  • pages/api/graphql.js routes to Yoga
  • Yoga handler: lib/graphql/yogaHandler.ts
    • createYoga with 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 by server/graphql/schema/index.js via @graphql-tools/merge

Resolvers:

  • server/graphql/resolvers/index.js is the entry point
  • server/graphql/resolvers/**/* map fields/mutations/queries to services or Fauna
  • Many resolvers in JS/TS; newer services are in TS under services/tenant/* and services/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) in server/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.id is explicitly allowlisted in LIGHTWEIGHT_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

  1. Ensure the query (and its resolvers) truly does not require full context fields (tenant, DB, flags, settings, plan, etc.).
  2. Add the Relay operation id to the allowlist in server/graphql/helpers/lightweightContext.ts (LIGHTWEIGHT_QUERIES).
  3. 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.isLightweight to make the decision explicit.

Relay:

  • Relay client/server environments under lib/createEnvironment/*
  • Relay compiler config in relay.config.js (Flow types, artifacts in __generated__)