From 50d99908a48ae68a5232dec0fc1f206be2b8652c Mon Sep 17 00:00:00 2001 From: Brian Cooper Date: Sun, 8 Nov 2026 10:05:30 -0700 Subject: [PATCH 1/2] docs(lattice): document REST connectors Lattice now federates REST APIs as subgraphs. Add a REST Connectors page and a configuration section covering the `rest` mapping (base_url, headers, and the per-field path/query/select options), name REST alongside GraphQL in the overview, and add the page to the nav. --- .../docs/products/lattice/configuration.mdx | 36 +++++++ content/docs/products/lattice/index.mdx | 5 +- content/docs/products/lattice/meta.json | 2 + .../docs/products/lattice/rest-connectors.mdx | 98 +++++++++++++++++++ 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 content/docs/products/lattice/rest-connectors.mdx diff --git a/content/docs/products/lattice/configuration.mdx b/content/docs/products/lattice/configuration.mdx index 2131a00..9f84bcc 100644 --- a/content/docs/products/lattice/configuration.mdx +++ b/content/docs/products/lattice/configuration.mdx @@ -47,6 +47,42 @@ subgraphs: Authorization: "Bearer ${SUBGRAPH_TOKEN}" ``` +## REST Connectors + +Federate a REST API as a subgraph. Declare the subgraph's GraphQL shape with a `schema` (used by `lattice compose`) and map its root fields to HTTP requests under `rest`. A REST subgraph needs no `url`: + +```yaml +subgraphs: + petstore: + schema: ./schemas/petstore.graphql + rest: + base_url: https://petstore.example.com + headers: + Authorization: "Bearer ${PETSTORE_TOKEN}" + fields: + pet: + path: /pets/{id} # {id} is filled from the field arguments + select: /data # optional JSON Pointer into the response body + pets: + method: GET # defaults to GET + path: /pets + query: + status: state # ?status= +``` + +At runtime the planner routes fetches to `petstore` like any subgraph. The connector interpolates arguments into `path`, adds the mapped `query` parameters, attaches `headers`, calls the upstream, and returns the JSON (optionally narrowed by `select`) as the field result. + +| Field | Purpose | +| --- | --- | +| `base_url` | Prepended to every field `path`. | +| `headers` | Static headers sent on every request. | +| `fields..method` | HTTP method (defaults to `GET`). | +| `fields..path` | Path template; `{arg}` placeholders come from the field arguments. | +| `fields..query` | Query parameters, mapping a parameter name to an argument name. | +| `fields..select` | Optional JSON Pointer selecting a sub-value of the response body. | + +Current scope is root query fields. Entity resolution (`@key` / `_entities`) into REST and OpenAPI schema generation are on the roadmap. + ## Caching Response caching via Valkey/Redis: diff --git a/content/docs/products/lattice/index.mdx b/content/docs/products/lattice/index.mdx index 2e9504d..b4abc24 100644 --- a/content/docs/products/lattice/index.mdx +++ b/content/docs/products/lattice/index.mdx @@ -35,12 +35,12 @@ import { FaNetworkWired, FaProjectDiagram } from "react-icons/fa"; alerts={[ { title: "💡 What is Lattice?", - description: "GraphQL Federation gateway for composing multiple services into a unified API", + description: "Federation gateway that composes GraphQL and REST services into one unified API", }, ]} /> -**Omni Lattice** is a GraphQL Federation gateway that composes multiple subgraph services into a unified supergraph API. Built from the ground up in Rust with an Apache 2.0 license. +**Omni Lattice** is a federation gateway that composes multiple services, GraphQL subgraphs and REST APIs alike, into a unified supergraph API. Built from the ground up in Rust with an Apache 2.0 license. ## Quick Start @@ -104,6 +104,7 @@ docker run -p 4000:4000 \ ## Key Features - **GraphQL Federation v2**: Query planning and execution across subgraphs +- **REST Connectors**: Federate REST APIs as subgraphs, mapping GraphQL fields to HTTP endpoints - **`@defer` Support**: Incremental delivery via `multipart/mixed` responses - **Request Deduplication**: Coalesce identical in-flight subgraph fetches - **Directive-Based Authorization**: Enforce `@requiresScopes` and `@requiresAuthentication` diff --git a/content/docs/products/lattice/meta.json b/content/docs/products/lattice/meta.json index 39f9731..917b679 100644 --- a/content/docs/products/lattice/meta.json +++ b/content/docs/products/lattice/meta.json @@ -2,6 +2,8 @@ "title": "🔲 Lattice", "pages": [ "configuration", + "---Sources---", + "rest-connectors", "---Features---", "authentication", "plugins", diff --git a/content/docs/products/lattice/rest-connectors.mdx b/content/docs/products/lattice/rest-connectors.mdx new file mode 100644 index 0000000..aad3e54 --- /dev/null +++ b/content/docs/products/lattice/rest-connectors.mdx @@ -0,0 +1,98 @@ +--- +title: REST Connectors +description: Federate REST APIs as subgraphs in a Lattice supergraph +--- + +Lattice federates more than GraphQL. A **REST connector** exposes a REST API to the graph as a subgraph: map its fields to HTTP requests, and Lattice plans and executes queries across it alongside your GraphQL subgraphs. + +## How it works + +A subgraph is backed by REST when it carries a `rest` block instead of a GraphQL `url`: + +- **Composition.** `lattice compose` reads the subgraph's `schema` (its SDL) and composes it into the supergraph, so the planner knows the REST subgraph's types and fields. +- **Execution.** At query time the planner routes fetches to the subgraph like any other. The connector translates each subquery into HTTP calls: it interpolates field arguments into the path, adds query parameters, attaches headers, and shapes the JSON response back into GraphQL. + +No HTTP introspection happens for a REST subgraph; its shape comes entirely from the `schema` you provide. + +## Example + +Describe the subgraph's shape in SDL: + +```graphql +# schemas/petstore.graphql +type Pet { + id: ID! + name: String! + status: String! +} + +type Query { + pet(id: ID!): Pet + pets(status: String): [Pet!]! +} +``` + +Map its fields to the REST API: + +```yaml +# lattice.yaml +supergraph: + path: ./supergraph.graphql + +subgraphs: + petstore: + schema: ./schemas/petstore.graphql + rest: + base_url: https://petstore.example.com + headers: + Authorization: "Bearer ${PETSTORE_TOKEN}" + fields: + pet: + path: /pets/{id} + select: /data + pets: + path: /pets + query: + status: status +``` + +Compose and run: + +```bash +lattice compose --config lattice.yaml --output supergraph.graphql +lattice serve --config lattice.yaml +``` + +A client query now resolves over REST: + +```graphql +query { + pet(id: "7") { + name + status + } +} +``` + +Lattice calls `GET https://petstore.example.com/pets/7`, reads `/data` from the response body, and returns it as `pet`. + +## Mapping reference + +| Field | Purpose | +| --- | --- | +| `base_url` | Base URL prepended to every field `path`. | +| `headers` | Static headers sent on every request. | +| `fields..method` | HTTP method. Defaults to `GET`. | +| `fields..path` | Path template appended to `base_url`. `{arg}` placeholders are filled from the field arguments. | +| `fields..query` | Query-string parameters, mapping a parameter name to a field argument name. A parameter is omitted when its argument is absent. | +| `fields..select` | Optional [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) selecting a sub-value of the response body as the field result. | + +Arguments may be literals or GraphQL variables; variables are resolved before the request is built. + +## Scope + +REST connectors currently cover **root query fields**. On the roadmap: + +- Entity resolution (`@key` / `_entities`) so a REST source can resolve entities referenced by other subgraphs. +- OpenAPI ingestion to generate the subgraph SDL and mappings from a spec. +- Mutations and additional upstream protocols. From 0403b5d326ffa20c9ed49e5808a1f78ac21914b1 Mon Sep 17 00:00:00 2001 From: Brian Cooper Date: Sun, 8 Nov 2026 10:16:07 -0700 Subject: [PATCH 2/2] docs(lattice): cover REST mutations and entity resolution REST connectors now map mutations to write methods with a JSON `body` and resolve federated `@key` references via per-type `entities` resolvers. Document both in the REST Connectors page and the configuration reference, and update the scope to leave OpenAPI generation as the remaining roadmap item. --- .../docs/products/lattice/configuration.mdx | 4 +- .../docs/products/lattice/rest-connectors.mdx | 53 +++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/content/docs/products/lattice/configuration.mdx b/content/docs/products/lattice/configuration.mdx index 9f84bcc..2345df9 100644 --- a/content/docs/products/lattice/configuration.mdx +++ b/content/docs/products/lattice/configuration.mdx @@ -80,8 +80,10 @@ At runtime the planner routes fetches to `petstore` like any subgraph. The conne | `fields..path` | Path template; `{arg}` placeholders come from the field arguments. | | `fields..query` | Query parameters, mapping a parameter name to an argument name. | | `fields..select` | Optional JSON Pointer selecting a sub-value of the response body. | +| `fields..body` | For write methods, the argument sent as the JSON request body. | +| `entities.` | Resolver that fetches one `` by its `@key` fields, for federated `_entities` resolution. | -Current scope is root query fields. Entity resolution (`@key` / `_entities`) into REST and OpenAPI schema generation are on the roadmap. +REST connectors cover query fields, mutations, and entity resolution. See [REST Connectors](./rest-connectors) for the full guide. OpenAPI schema generation is on the roadmap. ## Caching diff --git a/content/docs/products/lattice/rest-connectors.mdx b/content/docs/products/lattice/rest-connectors.mdx index aad3e54..1ce3cb4 100644 --- a/content/docs/products/lattice/rest-connectors.mdx +++ b/content/docs/products/lattice/rest-connectors.mdx @@ -76,6 +76,51 @@ query { Lattice calls `GET https://petstore.example.com/pets/7`, reads `/data` from the response body, and returns it as `pet`. +## Mutations + +Map a GraphQL mutation to a write method and send a JSON body with `body`, naming the argument whose value is the payload: + +```yaml +subgraphs: + petstore: + schema: ./schemas/petstore.graphql + rest: + base_url: https://petstore.example.com + fields: + createPet: + method: POST + path: /pets + body: input # the `input` argument is sent as the JSON body +``` + +```graphql +mutation { + createPet(input: { name: "Rex" }) { + id + } +} +``` + +Lattice sends `POST /pets` with `{"name":"Rex"}` and returns the response as `createPet`. + +## Entity resolution + +A REST source can resolve entities that other subgraphs reference by `@key`. Declare an `entities` resolver per type; the representation's key fields fill the resolver `path`: + +```yaml +subgraphs: + petstore: + schema: ./schemas/petstore.graphql + rest: + base_url: https://petstore.example.com + entities: + Pet: + path: /pets/{id} # {id} comes from the entity's @key fields + select: /data +``` + +When another subgraph yields a `Pet` by its key, Lattice calls `GET /pets/{id}` for each referenced entity and merges the result into the graph. A single `_entities` fetch resolves its representations in order, one REST call each. + ## Mapping reference | Field | Purpose | @@ -86,13 +131,15 @@ Lattice calls `GET https://petstore.example.com/pets/7`, reads `/data` from the | `fields..path` | Path template appended to `base_url`. `{arg}` placeholders are filled from the field arguments. | | `fields..query` | Query-string parameters, mapping a parameter name to a field argument name. A parameter is omitted when its argument is absent. | | `fields..select` | Optional [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) selecting a sub-value of the response body as the field result. | +| `fields..body` | For write methods, the argument whose value is sent as the JSON request body. | +| `entities.` | An entity resolver (same shape as a field mapping) that fetches one `` by its `@key` fields. | Arguments may be literals or GraphQL variables; variables are resolved before the request is built. ## Scope -REST connectors currently cover **root query fields**. On the roadmap: +REST connectors cover query fields, mutations, and federated entity resolution. On the roadmap: -- Entity resolution (`@key` / `_entities`) so a REST source can resolve entities referenced by other subgraphs. - OpenAPI ingestion to generate the subgraph SDL and mappings from a spec. -- Mutations and additional upstream protocols. +- Response field mapping for upstreams whose JSON shape differs from the schema. +- Additional upstream protocols.