|
| 1 | +# Progressive Override |
| 2 | + |
| 3 | +As a supergraph evolves, you often need to move fields from one subgraph to another. For example, |
| 4 | +imagine you are migrating the `status` of an `Order` from a general `orders` subgraph to a new, more |
| 5 | +specialized `fulfillment` subgraph. |
| 6 | + |
| 7 | +## Feature Flag Approach |
| 8 | + |
| 9 | +The `@override` directive in Apollo Federation is used for this, but making this change for all |
| 10 | +traffic at once can be risky. Progressive override allows for a safer, incremental migration by |
| 11 | +using a `label` on the directive: |
| 12 | + |
| 13 | +```graphql filename="fulfillment-subgraph.graphql" |
| 14 | +extend schema @link(url: "https://specs.apollo.dev/federation/v2.7", import: ["@key", "@override"]) |
| 15 | + |
| 16 | +type Order @key(fields: "id") { |
| 17 | + id: ID! |
| 18 | + # The "use-fulfillment-service" label controls this override |
| 19 | + status: String! @override(from: "orders", label: "use-fulfillment-service") |
| 20 | +} |
| 21 | +``` |
| 22 | + |
| 23 | +When a label like `"use-fulfillment-service"` is "active" for a request, the gateway will resolve |
| 24 | +`Order.status` from the new `fulfillment` subgraph. When it's inactive, it will continue to use the |
| 25 | +original `orders` subgraph. |
| 26 | + |
| 27 | +The `progressiveOverride` configuration in the gateway is the mechanism that determines which labels |
| 28 | +are active for any given request. |
| 29 | + |
| 30 | +```ts filename="gateway-config.ts" |
| 31 | +import { defineConfig, type GatewayContext } from '@graphql-hive/gateway' |
| 32 | + |
| 33 | +export const gatewayConfig = defineConfig({ |
| 34 | + progressiveOverride(label: string, context: GatewayContext) { |
| 35 | + if (label === 'use-fulfillment-service') { |
| 36 | + // Activate for 10% of requests |
| 37 | + return Math.random() < 0.1 |
| 38 | + // Or based on an environment variable |
| 39 | + return process.env.USE_FULFILLMENT_SERVICE === 'true' |
| 40 | + // Or based on a header |
| 41 | + return context.request.headers.get('X-Use-Fulfillment-Service') === 'true' |
| 42 | + } |
| 43 | + } |
| 44 | +}) |
| 45 | +``` |
| 46 | + |
| 47 | +## Percentage Approach |
| 48 | + |
| 49 | +You can use the built-in `percent(x)` label to gradually roll out overrides based on a percentage of |
| 50 | +requests without the need of any custom logic. |
| 51 | + |
| 52 | +```graphql filename="fulfillment-subgraph.graphql" |
| 53 | +extend schema @link(url: "https://specs.apollo.dev/federation/v2.7", import: ["@key", "@override"]) |
| 54 | + |
| 55 | +type Order @key(fields: "id") { |
| 56 | + id: ID! |
| 57 | + # The "percent" label controls this override |
| 58 | + status: String! @override(from: "orders", label: "percent(25)") |
| 59 | + # Now 25% of requests will use the fulfillment subgraph for Order.status |
| 60 | +} |
| 61 | +``` |
0 commit comments