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/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 921a0d69..606adf68 100644 --- a/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx +++ b/packages/documentation/content/docs/router/configuration/override_subgraph_urls.mdx @@ -2,38 +2,78 @@ 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 (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: - # The name of the subgraph to override - products: - url: # ... url definition - reviews: - url: # ... url definition + all: # ... global static URL or expression + subgraphs: + products: # ... static URL + reviews: + expression: # ... expression ``` ## Options -### `url` +### `all` + +- **Type:** `string` or `object` +- **Required:** No + +`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: + +- `.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. + +```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.` - **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 @@ -42,8 +82,8 @@ 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: "https://products.staging.svc.cluster.local/" ``` #### Dynamic URL with `expression` @@ -54,16 +94,16 @@ 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, 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: + subgraphs: + reviews: expression: | if .request.headers."x-region" == "eu" { "https://reviews.eu.api/graphql" 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..b7778236 100644 --- a/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx +++ b/packages/documentation/content/docs/router/guides/dynamic-subgraph-routing.mdx @@ -21,13 +21,14 @@ 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: + subgraphs: + subgraph_name: expression: | if .request.headers."x-use-special-instance" == "true" { "https://special-instance.com/graphql" @@ -53,8 +54,8 @@ to all users. ```yaml title="router.config.yaml" override_subgraph_urls: - products: - url: + subgraphs: + products: expression: | if .request.headers."x-deploy-track" == "canary" { "https://products-canary.example.com/graphql" @@ -73,8 +74,8 @@ users. ```yaml title="router.config.yaml" override_subgraph_urls: - products: - url: + subgraphs: + products: expression: | # Route 10% of traffic to canary if random_int(1, 100) <= 10 { @@ -95,8 +96,8 @@ regions. Routing users to the instance closest to them can significantly reduce ```yaml title="router.config.yaml" override_subgraph_urls: - reviews: - url: + subgraphs: + reviews: expression: | region = .request.headers."x-user-region" || "unknown"