diff --git a/packages/documentation/content/docs/router/configuration/expressions.mdx b/packages/documentation/content/docs/router/configuration/expressions.mdx index 9d04b0d3..2854bbd0 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 `/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"`). @@ -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..416822de 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,74 @@ 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, 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: /graphql/{wildcard} +override_subgraph_urls: + all: + expression: | + segment = string!(.request.url_matches.wildcard) + replace(string!(.default), "/api/", "/api/" + segment + "/") +``` + +### `subgraphs..url` - **Type:** `string` or `object` - **Required:** Yes @@ -42,8 +84,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 +97,21 @@ 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: - 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 + } ```