From 0b68dbbb475d8605dbda12a5d27059e54ca517aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 15:47:35 +0000 Subject: [PATCH 1/3] docs(router): update override_subgraph_urls docs for new all/subgraphs shape Agent-Logs-Url: https://github.com/graphql-hive/docs/sessions/58eeea55-7de7-4dfe-916a-70e0c4e277e2 Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com> --- .../docs/router/configuration/expressions.mdx | 7 +- .../configuration/override_subgraph_urls.mdx | 98 ++++++++++++++----- .../guides/dynamic-subgraph-routing.mdx | 85 ++++++++-------- 3 files changed, 122 insertions(+), 68 deletions(-) diff --git a/packages/documentation/content/docs/router/configuration/expressions.mdx b/packages/documentation/content/docs/router/configuration/expressions.mdx index 9d04b0d3..ac460747 100644 --- a/packages/documentation/content/docs/router/configuration/expressions.mdx +++ b/packages/documentation/content/docs/router/configuration/expressions.mdx @@ -60,6 +60,8 @@ Represents the incoming HTTP request. It exposes nested fields such as: - `.request.url.host` - the request host (e.g. `api.example.com`). - `.request.url.port` - the request port (e.g. `443`). - `.request.url.path` - the request path (e.g. `/graphql`). +- `.request.url_matches` - path parameters captured from `http.graphql_endpoint` patterns (for + example, with `/{tenant}/graphql`, `.request.url_matches.tenant` contains the matched value). - `.request.operation.name` - the name of the GraphQL operation being executed, if provided. - `.request.operation.type` - the type of GraphQL operation being executed (e.g. `"query"`, `"mutation"`, or `"subscription"`). @@ -79,8 +81,9 @@ not yet exist. ### `.subgraph` -Available in both **request** and **response** header rules. It provides metadata about the subgraph -handling the current request, including: +Available in [dynamic routing expressions](./override_subgraph_urls), **request** header rules, and +**response** header rules. It provides metadata about the subgraph handling the current request, +including: - `.subgraph.name` - the name of the subgraph as defined in your supergraph schema. diff --git a/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx b/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx index 921a0d69..85ba5407 100644 --- a/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx +++ b/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx @@ -2,32 +2,75 @@ title: "override_subgraph_urls" --- -The `override_subgraph_urls` configuration allows you to dynamically change the URL for a subgraph -at runtime, based on the properties of an incoming request. +The `override_subgraph_urls` configuration allows you to dynamically change subgraph URLs at runtime +based on the incoming request. This is the primary mechanism for implementing advanced routing patterns. For detailed guides and use cases, see the [Dynamic Subgraph Routing](/docs/router/guides/dynamic-subgraph-routing) guide. ## Configuration Structure -The `override_subgraph_urls` key is a top-level object in your `router.config.yaml`. The keys within -this object are the names of the subgraphs you wish to override, as they appear in your supergraph -schema. +The `override_subgraph_urls` key is a top-level object in your `router.config.yaml`. +It supports two override scopes: -For each subgraph, you must specify a `url` property. +- `subgraphs`: Per-subgraph URL overrides keyed by subgraph name. +- `all`: A single override expression applied to all subgraphs that do not have a dedicated + override under `subgraphs`. + +Per-subgraph overrides always take precedence over `all`. ```yaml override_subgraph_urls: - # The name of the subgraph to override - products: - url: # ... url definition - reviews: - url: # ... url definition + all: + expression: # ... global expression + subgraphs: + products: + url: # ... url definition + reviews: + url: # ... url definition ``` ## Options -### `url` +### `all` + +- **Type:** `object` +- **Required:** No + +`all.expression` lets you define one routing expression that applies to every subgraph without its +own entry under `subgraphs`. + +Within the `expression`, you have access to: + +- `.request`: The incoming HTTP request object (headers, query parameters, parsed operation, and + `url_matches`). +- `.default`: The original subgraph URL from the supergraph schema. +- `.subgraph.name`: The name of the subgraph currently being resolved. + +```yaml +override_subgraph_urls: + all: + expression: | + if .subgraph.name == "products" && .request.headers."x-region" == "us-east" { + "https://products-us-east.example.com/graphql" + } else { + .default + } +``` + +If `http.graphql_endpoint` uses path parameters, they are available under `.request.url_matches`: + +```yaml +http: + graphql_endpoint: /{tenant}/graphql +override_subgraph_urls: + all: + expression: | + tenant = string!(.request.url_matches.tenant) + replace(string!(.default), "/api/", "/api/" + tenant + "/") +``` + +### `subgraphs..url` - **Type:** `string` or `object` - **Required:** Yes @@ -42,8 +85,9 @@ is useful for permanently redirecting a subgraph without recomposing your superg ```yaml override_subgraph_urls: - products: - url: "https://products.staging.svc.cluster.local/" + subgraphs: + products: + url: "https://products.staging.svc.cluster.local/" ``` #### Dynamic URL with `expression` @@ -54,20 +98,22 @@ decisions. - `expression`: **(string, required)** An [expression](./expressions) that computes the new URL. -Within the `expression`, you have access to two key variables: +Within the `expression`, you have access to: -- `.request`: The incoming HTTP request object, including its headers. -- `.default`: The original subgraph URL from the supergraph schema, which should be used as a - fallback. +- `.request`: The incoming HTTP request object (headers, query parameters, parsed operation, and + `url_matches`). +- `.default`: The original subgraph URL from the supergraph schema. +- `.subgraph.name`: The name of the subgraph currently being resolved. ```yaml override_subgraph_urls: - reviews: - url: - expression: | - if .request.headers."x-region" == "eu" { - "https://reviews.eu.api/graphql" - } else { - .default - } + subgraphs: + reviews: + url: + expression: | + if .request.headers."x-region" == "eu" { + "https://reviews.eu.api/graphql" + } else { + .default + } ``` diff --git a/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx b/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx index 274cc995..0307ef63 100644 --- a/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx +++ b/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx @@ -21,19 +21,21 @@ For each request, the router evaluates your expression and routes to the URL it - `.request` - The incoming HTTP request (headers, method, etc.) - `.default` - The default URL from your supergraph schema +- `.subgraph.name` - The current subgraph name Simple example configuration that routes based on a runtime condition: ```yaml title="router.config.yaml" override_subgraph_urls: - subgraph_name: - url: - expression: | - if .request.headers."x-use-special-instance" == "true" { - "https://special-instance.com/graphql" - } else { - .default # Always provide a fallback - } + subgraphs: + subgraph_name: + url: + expression: | + if .request.headers."x-use-special-instance" == "true" { + "https://special-instance.com/graphql" + } else { + .default # Always provide a fallback + } ``` ## Examples @@ -53,14 +55,15 @@ to all users. ```yaml title="router.config.yaml" override_subgraph_urls: - products: - url: - expression: | - if .request.headers."x-deploy-track" == "canary" { - "https://products-canary.example.com/graphql" - } else { - .default - } + subgraphs: + products: + url: + expression: | + if .request.headers."x-deploy-track" == "canary" { + "https://products-canary.example.com/graphql" + } else { + .default + } ``` With this configuration, your QA team or CI/CD pipeline can test the new deployment in production by @@ -73,15 +76,16 @@ users. ```yaml title="router.config.yaml" override_subgraph_urls: - products: - url: - expression: | - # Route 10% of traffic to canary - if random_int(1, 100) <= 10 { - "https://products-canary.example.com/graphql" - } else { - .default - } + subgraphs: + products: + url: + expression: | + # Route 10% of traffic to canary + if random_int(1, 100) <= 10 { + "https://products-canary.example.com/graphql" + } else { + .default + } ``` @@ -95,19 +99,20 @@ regions. Routing users to the instance closest to them can significantly reduce ```yaml title="router.config.yaml" override_subgraph_urls: - reviews: - url: - expression: | - region = .request.headers."x-user-region" || "unknown" - - if region == "us-east" { - "https://reviews-us-east.example.com/graphql" - } else if region == "eu-west" { - "https://reviews-eu-west.example.com/graphql" - } else if region == "asia-pacific" { - "https://reviews-ap.example.com/graphql" - } else { - # Default to primary region - .default - } + subgraphs: + reviews: + url: + expression: | + region = .request.headers."x-user-region" || "unknown" + + if region == "us-east" { + "https://reviews-us-east.example.com/graphql" + } else if region == "eu-west" { + "https://reviews-eu-west.example.com/graphql" + } else if region == "asia-pacific" { + "https://reviews-ap.example.com/graphql" + } else { + # Default to primary region + .default + } ``` From eddd5067fec26d4a67399c467ed58842c086955c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 16:01:50 +0000 Subject: [PATCH 2/3] docs(router): address review follow-ups on request context examples Agent-Logs-Url: https://github.com/graphql-hive/docs/sessions/2eb9a164-70db-4cd9-9dc7-89ff7b2f2f49 Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com> --- .../docs/router/configuration/expressions.mdx | 2 +- .../router/configuration/override_subgraph_urls.mdx | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/documentation/content/docs/router/configuration/expressions.mdx b/packages/documentation/content/docs/router/configuration/expressions.mdx index ac460747..2854bbd0 100644 --- a/packages/documentation/content/docs/router/configuration/expressions.mdx +++ b/packages/documentation/content/docs/router/configuration/expressions.mdx @@ -61,7 +61,7 @@ Represents the incoming HTTP request. It exposes nested fields such as: - `.request.url.port` - the request port (e.g. `443`). - `.request.url.path` - the request path (e.g. `/graphql`). - `.request.url_matches` - path parameters captured from `http.graphql_endpoint` patterns (for - example, with `/{tenant}/graphql`, `.request.url_matches.tenant` contains the matched value). + example, with `/graphql/{wildcard}`, `.request.url_matches.wildcard` contains the matched value). - `.request.operation.name` - the name of the GraphQL operation being executed, if provided. - `.request.operation.type` - the type of GraphQL operation being executed (e.g. `"query"`, `"mutation"`, or `"subscription"`). diff --git a/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx b/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx index 85ba5407..416822de 100644 --- a/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx +++ b/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx @@ -42,8 +42,7 @@ own entry under `subgraphs`. Within the `expression`, you have access to: -- `.request`: The incoming HTTP request object (headers, query parameters, parsed operation, and - `url_matches`). +- `.request`: The incoming HTTP request object (headers, parsed operation, and `url_matches`). - `.default`: The original subgraph URL from the supergraph schema. - `.subgraph.name`: The name of the subgraph currently being resolved. @@ -62,12 +61,12 @@ If `http.graphql_endpoint` uses path parameters, they are available under `.requ ```yaml http: - graphql_endpoint: /{tenant}/graphql + graphql_endpoint: /graphql/{wildcard} override_subgraph_urls: all: expression: | - tenant = string!(.request.url_matches.tenant) - replace(string!(.default), "/api/", "/api/" + tenant + "/") + segment = string!(.request.url_matches.wildcard) + replace(string!(.default), "/api/", "/api/" + segment + "/") ``` ### `subgraphs..url` @@ -100,8 +99,7 @@ decisions. Within the `expression`, you have access to: -- `.request`: The incoming HTTP request object (headers, query parameters, parsed operation, and - `url_matches`). +- `.request`: The incoming HTTP request object (headers, parsed operation, and `url_matches`). - `.default`: The original subgraph URL from the supergraph schema. - `.subgraph.name`: The name of the subgraph currently being resolved. From ef0502a79f19e31a267f5b1e54f2616e41f0a06d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 15:00:40 +0000 Subject: [PATCH 3/3] docs(router): sync override_subgraph_urls docs with latest router#987 shape Agent-Logs-Url: https://github.com/graphql-hive/docs/sessions/5fb96f77-31db-45cc-8ed9-104683082404 Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com> --- .../docs/router/configuration/expressions.mdx | 2 +- .../docs/router/configuration/http.mdx | 5 +- .../configuration/override_subgraph_urls.mdx | 46 ++++++------- .../guides/dynamic-subgraph-routing.mdx | 68 +++++++++---------- 4 files changed, 57 insertions(+), 64 deletions(-) diff --git a/packages/documentation/content/docs/router/configuration/expressions.mdx b/packages/documentation/content/docs/router/configuration/expressions.mdx index 2854bbd0..ac460747 100644 --- a/packages/documentation/content/docs/router/configuration/expressions.mdx +++ b/packages/documentation/content/docs/router/configuration/expressions.mdx @@ -61,7 +61,7 @@ Represents the incoming HTTP request. It exposes nested fields such as: - `.request.url.port` - the request port (e.g. `443`). - `.request.url.path` - the request path (e.g. `/graphql`). - `.request.url_matches` - path parameters captured from `http.graphql_endpoint` patterns (for - example, with `/graphql/{wildcard}`, `.request.url_matches.wildcard` contains the matched value). + example, with `/{tenant}/graphql`, `.request.url_matches.tenant` contains the matched value). - `.request.operation.name` - the name of the GraphQL operation being executed, if provided. - `.request.operation.type` - the type of GraphQL operation being executed (e.g. `"query"`, `"mutation"`, or `"subscription"`). diff --git a/packages/documentation/content/docs/router/configuration/http.mdx b/packages/documentation/content/docs/router/configuration/http.mdx index ae40efa6..b870d8bd 100644 --- a/packages/documentation/content/docs/router/configuration/http.mdx +++ b/packages/documentation/content/docs/router/configuration/http.mdx @@ -50,8 +50,9 @@ container CPU limit to avoid oversubscribed worker threads. The `graphql_endpoint` property specifies the URL path at which the router will expose its GraphQL API. -You may also use `/graphql/{wildcard}` if you wish to capture nested paths within the same request, -or `/graphql/{tail}*` to capture any remaining path segments. +You may also use named path parameters such as `/{tenant}/graphql`, `/graphql/{wildcard}` if you +wish to capture nested paths within the same request, or `/graphql/{tail}*` to capture any +remaining path segments. ## Example diff --git a/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx b/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx index 416822de..606adf68 100644 --- a/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx +++ b/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx @@ -14,31 +14,29 @@ The `override_subgraph_urls` key is a top-level object in your `router.config.ya It supports two override scopes: - `subgraphs`: Per-subgraph URL overrides keyed by subgraph name. -- `all`: A single override expression applied to all subgraphs that do not have a dedicated - override under `subgraphs`. +- `all`: A single override (static URL or expression) applied to all subgraphs that do not have a + dedicated override under `subgraphs`. Per-subgraph overrides always take precedence over `all`. ```yaml override_subgraph_urls: - all: - expression: # ... global expression + all: # ... global static URL or expression subgraphs: - products: - url: # ... url definition + products: # ... static URL reviews: - url: # ... url definition + expression: # ... expression ``` ## Options ### `all` -- **Type:** `object` +- **Type:** `string` or `object` - **Required:** No -`all.expression` lets you define one routing expression that applies to every subgraph without its -own entry under `subgraphs`. +`all` lets you define a global override for every subgraph without its own entry under `subgraphs`. +It can be a static URL string or an object with an `expression`. Within the `expression`, you have access to: @@ -61,21 +59,21 @@ If `http.graphql_endpoint` uses path parameters, they are available under `.requ ```yaml http: - graphql_endpoint: /graphql/{wildcard} + graphql_endpoint: /{tenant}/graphql override_subgraph_urls: all: expression: | - segment = string!(.request.url_matches.wildcard) - replace(string!(.default), "/api/", "/api/" + segment + "/") + tenant = string!(.request.url_matches.tenant) + replace(string!(.default), "/api/", "/api/" + tenant + "/") ``` -### `subgraphs..url` +### `subgraphs.` - **Type:** `string` or `object` - **Required:** Yes -The `url` property defines the new URL for the subgraph. It can be provided in two forms: a static -string or an object for dynamic evaluation. +Each `subgraphs.` entry defines the new URL for that subgraph. It can be provided in two +forms: a static string or an object for dynamic evaluation. #### Static URL @@ -85,8 +83,7 @@ is useful for permanently redirecting a subgraph without recomposing your superg ```yaml override_subgraph_urls: subgraphs: - products: - url: "https://products.staging.svc.cluster.local/" + products: "https://products.staging.svc.cluster.local/" ``` #### Dynamic URL with `expression` @@ -107,11 +104,10 @@ Within the `expression`, you have access to: override_subgraph_urls: subgraphs: reviews: - url: - expression: | - if .request.headers."x-region" == "eu" { - "https://reviews.eu.api/graphql" - } else { - .default - } + expression: | + if .request.headers."x-region" == "eu" { + "https://reviews.eu.api/graphql" + } else { + .default + } ``` diff --git a/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx b/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx index 0307ef63..b7778236 100644 --- a/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx +++ b/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx @@ -29,13 +29,12 @@ Simple example configuration that routes based on a runtime condition: override_subgraph_urls: subgraphs: subgraph_name: - url: - expression: | - if .request.headers."x-use-special-instance" == "true" { - "https://special-instance.com/graphql" - } else { - .default # Always provide a fallback - } + expression: | + if .request.headers."x-use-special-instance" == "true" { + "https://special-instance.com/graphql" + } else { + .default # Always provide a fallback + } ``` ## Examples @@ -57,13 +56,12 @@ to all users. override_subgraph_urls: subgraphs: products: - url: - expression: | - if .request.headers."x-deploy-track" == "canary" { - "https://products-canary.example.com/graphql" - } else { - .default - } + expression: | + if .request.headers."x-deploy-track" == "canary" { + "https://products-canary.example.com/graphql" + } else { + .default + } ``` With this configuration, your QA team or CI/CD pipeline can test the new deployment in production by @@ -78,14 +76,13 @@ users. override_subgraph_urls: subgraphs: products: - url: - expression: | - # Route 10% of traffic to canary - if random_int(1, 100) <= 10 { - "https://products-canary.example.com/graphql" - } else { - .default - } + expression: | + # Route 10% of traffic to canary + if random_int(1, 100) <= 10 { + "https://products-canary.example.com/graphql" + } else { + .default + } ``` @@ -101,18 +98,17 @@ regions. Routing users to the instance closest to them can significantly reduce override_subgraph_urls: subgraphs: reviews: - url: - expression: | - region = .request.headers."x-user-region" || "unknown" - - if region == "us-east" { - "https://reviews-us-east.example.com/graphql" - } else if region == "eu-west" { - "https://reviews-eu-west.example.com/graphql" - } else if region == "asia-pacific" { - "https://reviews-ap.example.com/graphql" - } else { - # Default to primary region - .default - } + expression: | + region = .request.headers."x-user-region" || "unknown" + + if region == "us-east" { + "https://reviews-us-east.example.com/graphql" + } else if region == "eu-west" { + "https://reviews-eu-west.example.com/graphql" + } else if region == "asia-pacific" { + "https://reviews-ap.example.com/graphql" + } else { + # Default to primary region + .default + } ```