gqlgw¶
A GraphQL API described in SDL, served by nginx, resolved by your REST services.
gqlgw is an SDL-first GraphQL gateway for OpenResty. You write a GraphQL schema and annotate its fields with the REST call that resolves them. gqlgw compiles the schema once, generates the nginx configuration, and answers GraphQL requests by calling your services. N+1 patterns are removed by batching, and a three-level resource cache sits in front of the services.
flowchart LR
client([GraphQL client]) -- "POST /graphql" --> gw
subgraph gw [nginx + gqlgw]
direction TB
c["libgql.so (C99)<br/>parse · validate · plan"]
l["Lua executor<br/>rounds · batching · cache"]
c --> l
end
l -- "GET /users?ids=1,2,3" --> users[(users service)]
l -- "GET /posts?limit=20" --> posts[(posts service)]
l <-. "multi-get / set" .-> mc[(memcached)]
In one example¶
type Query {
posts(limit: Int = 20): [Post!]! @fetch(source: "posts", path: "/posts?limit={args.limit}")
}
type Post {
title: String!
authorId: ID! @from(key: "author_id")
author: User!
@fetch(source: "users", path: "/users/{parent.authorId}")
@batch(path: "/users?ids={keys}", match: "id")
}
type User @cache(ttl: 300) {
id: ID!
name: String!
}
| Round | Source | Request | Why |
|---|---|---|---|
| 1 | posts |
GET /posts?limit=3 |
Query.posts |
| 2 | users |
GET /users?ids=2,3,4 |
the three Post.author fields, batched into one call |
The next identical query makes one call: the authors come from the cache.
What you get¶
-
SDL is the contract
Routing lives next to the fields it resolves:
@fetch,@batch,@cache,@from,@discriminator. The directives are predeclared and hidden from introspection. -
Compiled, never interpreted at start
gqlc compilechecks the schema and the configuration when the image is built. The gateway never starts from an uncompiled.graphqls. -
No N+1
Fields are resolved in rounds: every pending fetch of a round leaves at once, identical requests are merged, and
@batchfields share one call per round. -
A cache per REST resource
Per-worker LRU,
lua_shared_dict, then memcached. Cache keys are REST resources, so every query shares them. Purge one source with one request. -
nginx does the HTTP
gqlc renderturnsgqlgw.tomlinto an nginx block: upstreams with keepalive and DNS re-resolution, TLS verification, header allowlists, timeouts. -
Spec-conformant, and measured
Validation and introspection match graphql-js 17, checked by differential fuzzing. Prometheus metrics come built in.
Where to start¶
- Getting started: run the example gateway with Docker, then build your own.
- How it works: the architecture, the pipeline and the life of a request.
- Examples: full server, locations only, batching, auth forwarding, mutations.