GraphQL
The gateway ships a GraphQL-aware layer that fronts a GraphQL upstream. When enabled it parses each incoming operation, enforces depth/complexity/introspection policy, serves a real GraphiQL IDE, and proxies valid queries to your GraphQL backend through the normal routing, auth, rate-limit, and load-balancing pipeline.
This is single-graph support: the gateway puts a policy and IDE layer in front of one GraphQL upstream per endpoint. Multi-subgraph federation (schema composition, query planning, cross-subgraph entity resolution) is on the roadmap, not yet available.
How it works01
The GraphQL layer runs as a middleware inside the request pipeline — after authentication and rate limiting, before the proxy. For a request to the configured endpoint it will:
Serve a real GraphiQL IDE for browser requests — a
GETwhoseAcceptcontainstext/htmland which has noquery=parameter. The IDE is configured to talk to the same endpoint.Read the operation from a
POSTJSON body ({"query": "..."}) or from thequeryURL parameter on aGET.Parse the operation with a spec-compliant GraphQL parser and reject malformed queries.
Enforce query-depth and complexity limits, and introspection policy.
For a valid operation, hand the request back to the pipeline so it is proxied to the upstream declared by the matching route — with the gateway's routing, auth, rate limiting, and load balancing applied.
Policy rejections return a GraphQL error envelope ({"errors":[{"message": "..."}]}) so
GraphQL clients handle them normally.
Enabling it02
Add a graphql: block to the gateway config and declare a normal route for the endpoint
pointing at your GraphQL upstream. The middleware adds parsing and policy enforcement on top of
that route; the route itself does the routing and proxying.
graphql:
enabled: true
endpoint: /graphql # path the GraphQL layer intercepts
playground: true # serve GraphiQL on GET /graphql (HTML Accept)
introspection: true # allow __schema / __type queries
max_depth: 15 # reject operations nested deeper than this
max_complexity: 1000 # reject operations selecting more fields than this
upstreams:
- name: graphql-backend
instances:
- id: graphql-1
host: 127.0.0.1
port: 4000
routes:
- path: /graphql
methods: [GET, POST]
upstream: graphql-backendThe layer is disabled by default (enabled: false); existing deployments are unaffected
until you turn it on. If graphql.enabled is true but no route matches the endpoint path, a
request to it returns the gateway's normal "route not found" response — the route is what
supplies the upstream.
Configuration reference
| Field | Default | Description |
enabled | false | Turn the GraphQL-aware layer on. |
endpoint | /graphql | Path the layer intercepts. Other paths pass straight through. |
playground | true | Serve the GraphiQL IDE on an HTML GET to the endpoint. |
introspection | true | When false, operations selecting __schema/__type are rejected. |
max_depth | 15 | Maximum selection nesting depth (root selection set = depth 1). |
max_complexity | 1000 | Maximum number of selected fields (an approximate query cost). |
Subscriptions03
GraphQL subscriptions are typically delivered over WebSocket (graphql-ws /
graphql-transport-ws). The WebSocket proxy forwards the Sec-WebSocket-Protocol subprotocol,
so a subscription endpoint can be proxied as a normal WebSocket route. See
WebSocket.
Limitations04
Single-graph only. No schema composition, query planning, or cross-subgraph entity resolution yet — point the endpoint at one GraphQL upstream. (Federation is planned. The gateway's existing "federation" machinery is part of FARP service discovery, not GraphQL.)
Complexity is a field count.
max_complexityapproximates cost by counting selected fields; it is not type-weighted.Fragment spreads aren't expanded for depth/complexity analysis (named fragments are not resolved against a schema at this stage); inline fragments are analyzed at their enclosing level.
No query batching or persisted queries (APQ) yet.
Only the exact endpoint path is intercepted. Subpaths (e.g.
/graphql/foo) pass through as ordinary HTTP and are routed normally.
See also Routes, Routing, and HTTP/1.1 & HTTP/2.