API Gateway for GraphQL: Security, Cost, and Caching
API7.ai
April 25, 2025
An API gateway can put a consistent edge in front of a GraphQL service, but GraphQL changes what that edge must understand. A conventional gateway can terminate TLS, authenticate callers, route /graphql, limit request size, and collect traffic metrics. Query depth, field-level cost, persisted operations, and response caching require a GraphQL-aware plugin, router, or application—not merely a rule on the URL.
For protocol and schema fundamentals, start with what GraphQL is; this page focuses on the gateway boundary.
The safest architecture keeps the responsibilities explicit:
- the gateway owns edge transport and coarse traffic policy;
- a GraphQL-aware layer parses and costs operations;
- the GraphQL server and domain services enforce field- and object-level authorization;
- a federation router or application layer owns schema composition;
- a cache owns only responses with a verified identity and freshness policy.
Why GraphQL Changes Gateway Policy
REST-style policies often use an HTTP method and path as a useful operation boundary. Many GraphQL APIs receive different queries and mutations through one endpoint:
POST /graphql Content-Type: application/json { "operationName": "OrderDetails", "query": "query OrderDetails($id: ID!) { order(id: $id) { id status total } }", "variables": { "id": "ord_123" } }
The path alone does not reveal which fields will execute, how much data can fan out, or which object the caller is requesting. operationName is useful telemetry, but it is client input and is not an authorization decision. A gateway must parse the selected operation—or delegate to a component that does—before applying schema-aware policy.
Gateway Controls vs GraphQL-Aware Controls
| Control | Generic API gateway | GraphQL-aware component |
|---|---|---|
| TLS and client authentication | Yes | Usually consumes identity context |
| Route and body-size limits | Yes | May add document limits |
| Consumer/request rate limits | Yes | May charge by query cost |
| Query parsing and validation | Not automatic | Yes |
| Depth or field-cost calculation | Not automatic | Yes, with an explicit model |
| Field/object authorization | No | GraphQL server/domain services |
| Federation composition | No | GraphQL router/gateway designed for it |
| Response caching | HTTP rules only | Operation- and identity-aware cache |
Product names can blur this distinction: some products called “GraphQL gateways” are federation routers, while API gateways may add GraphQL plugins. Evaluate the actual execution path rather than the label.
A Safe GraphQL Request Path
flowchart TB
C[Client] --> E[API gateway edge]
E --> P[GraphQL-aware policy]
P --> R[GraphQL server or router]
R --> S[Domain services]
E -. TLS, identity, size, coarse quota .-> E
P -. parse, allowlist, depth or cost .-> P
R -. schema and resolver authorization .-> R
The gateway must strip or overwrite any client-supplied identity headers before adding trusted context for an upstream. Protect the gateway-to-upstream hop, and configure the upstream to trust identity context only from that controlled path. The application still verifies object-level access; a valid access token does not imply permission to read every order(id: ...).
Authentication and Authorization
Authenticate at the edge with the profile appropriate to the client:
- validate JWT access-token signature, issuer, audience, time claims, and required scopes;
- use authenticated token introspection for opaque tokens;
- use mTLS or a workload identity profile for service-to-service calls where required;
- never treat an ID token as an API access token.
Authorization then occurs at multiple layers:
- Gateway: coarse route, consumer, tenant, or scope policy.
- GraphQL operation: allowed persisted operation or approved operation class.
- Resolver/domain service: field, row, and object ownership checks using trusted caller context.
Do not authorize by searching the raw request body with a regular expression. Aliases, fragments, comments, variables, and multiple operations make text matching unreliable.
Query Depth, Complexity, and Abuse Controls
A deeply nested document can be expensive, but depth alone misses fan-out:
query { products(first: 10000) { reviews(first: 1000) { author { name } } } }
Both first arguments affect work even though the document's depth stays fixed. A production policy commonly combines:
- maximum request-body and parsed-document sizes;
- parser time and expansion bounds;
- maximum depth;
- field or node weights;
- pagination argument limits;
- per-operation maximum cost;
- cost-weighted quota per authenticated tenant or consumer;
- downstream timeouts and concurrency protection.
A cost model must be tested against the current schema and resolver behavior. Introspection may help a policy component obtain schema information, but disabling public introspection is not a complete defense against expensive queries. Attackers can infer or possess a schema, and known clients may still submit costly valid operations.
Apache APISIX GraphQL Cost Limits
Current Apache APISIX documentation includes a graphql-limit-count plugin that charges a fixed-window quota using the accumulated depth of GraphQL query ASTs. It is a depth-weighted counter, not a complete resolver-cost model; real field fan-out and backend work still need limits in a schema-aware GraphQL component. Important deployment boundaries include:
- only the documented request methods and content types are parsed;
- identity for the counter key must come from a verified consumer or variable;
- local counters are node-local; Redis policies are needed for shared counters;
- degradation behavior must match the application's abuse-risk policy.
Version-pin the configuration and run negative tests for fragments, multiple operations, variables, pagination, schema changes, and an unavailable counter backend.
GraphQL Caching Without Cross-User Leaks
Caching a GraphQL response only by /graphql is incorrect because many different operations share that URL. A safe cache key may need:
- normalized selected operation or persisted-operation hash;
- variables that affect the response;
- tenant or authenticated consumer identity;
- authorization-relevant claims;
- locale, version, and other approved variants;
- schema or deployment version when compatibility requires it.
Cache only read operations whose data and freshness policy permit reuse. Mutations must bypass response caching. User-specific, permission-dependent, rapidly changing, or sensitive data may be unsuitable even with an identity partition.
Current APISIX also documents graphql-proxy-cache, which derives a key from route/service/host context, identity, and the GraphQL body, and bypasses mutations. Its consumer_isolation protects separate namespaces only when APISIX has resolved a Consumer or remote_user; an arbitrary bearer token or tenant header does not automatically create that identity. Validate cache hits, misses, bypasses, TTLs, Set-Cookie, and purge authorization before production use.
Persisted operations can make caching and policy easier: the client sends an approved hash or identifier, and the server resolves it to a reviewed document. Treat the registry as a governed deployment artifact, reject unknown identifiers when allowlist mode is intended, and bind authorization to the resolved operation—not just the identifier supplied by the client.
Routing, Federation, and Protocol Boundaries
A generic API gateway can load balance GraphQL HTTP traffic among equivalent backends. It does not automatically merge schemas or plan a federated query. A dedicated GraphQL router typically owns subgraph discovery, composition, query planning, and subgraph execution; see the separate GraphQL federation overview for that architecture.
Similarly, converting a fixed HTTP route into a predefined upstream GraphQL query is different from exposing arbitrary protocol translation. APISIX's degraphql plugin maps a configured GraphQL document and named variables to an HTTP-facing route. It does not make the gateway a general schema-composition or business-orchestration engine.
Readers comparing Amazon API Gateway with GraphQL should not treat API Gateway as a GraphQL execution layer. Amazon API Gateway fronts HTTP, REST, and WebSocket APIs, while AWS AppSync is AWS's managed GraphQL service. Putting an HTTP gateway in front of a GraphQL server does not add schema execution by itself.
Observability and Data Handling
Useful GraphQL telemetry includes:
- approved operation name or persisted-operation ID;
- computed cost and rejection reason;
- gateway, router, resolver, and upstream latency;
- response status plus GraphQL error classification;
- cache status;
- tenant-safe quota usage.
Do not log raw access tokens, cookies, variables, or entire query/response bodies by default. Variables often contain personal or business data, and a GraphQL response can return partial data alongside errors. Apply allowlisted structured logging, redaction, access control, and retention at every sink.
An HTTP 200 response can still contain GraphQL errors, so transport status alone is not an application-success metric. Instrument the GraphQL server or router and propagate trace context across the trusted boundary.
Deployment Checklist
- The gateway authenticates access tokens or workload identities with the intended issuer and audience.
- Client identity headers are stripped or overwritten, and the upstream hop is protected.
- Resolver/domain authorization covers fields and object ownership.
- Request size, parser work, depth, fan-out, and maximum cost have tested limits.
- Quotas use a verified consumer/tenant key and the required shared counter backend.
- Mutations and sensitive responses bypass caches; identity and variables are in the key where needed.
- Persisted-operation registration, rollout, and revocation are governed.
- Logs exclude secrets and sensitive variables; GraphQL errors are measured separately from HTTP status.
- Federation, workflow, and business consistency have named owners outside a generic edge gateway.
FAQ
Can an API gateway route GraphQL?
Yes. A generic gateway can proxy and load balance GraphQL over HTTP. Query-aware controls require a plugin or upstream component that parses GraphQL documents and understands the relevant schema or cost model.
Should production GraphQL disable introspection?
Restricting introspection may reduce casual discovery, but it is not a substitute for authentication, authorization, cost limits, allowlisted operations, and downstream protection.
Can a gateway cache GraphQL POST responses?
Some GraphQL-aware gateways can, but only with an operation-, variable-, identity-, and freshness-aware policy. Do not rely on the URL alone, and always bypass mutations.
Is a GraphQL gateway the same as an API gateway?
Not necessarily. “GraphQL gateway” often means a schema-composition or federation router. A general API gateway focuses on edge traffic policy. One product may implement both roles, but the responsibilities should still be evaluated separately.
Summary
An API gateway is valuable in front of GraphQL when it provides a controlled edge and delegates schema-aware work correctly. The reliable design authenticates at the edge, authorizes again at resolver and object boundaries, prices query work with a tested model, isolates caches by identity and operation, and keeps federation and durable business workflows in purpose-built components.