|
| 1 | +--- |
| 2 | +title: Backward Compatibility in Apollo Federation 2 |
| 3 | +subtitle: Navigating the transition from Apollo Federation 1 to Federation 2 |
| 4 | +description: Frequently asked questions when transitioning from Apollo Federation 1 to Federation 2. |
| 5 | +--- |
| 6 | + |
| 7 | +## Is official support ending for `@apollo/gateway` v0.x? |
| 8 | + |
| 9 | +Yes. `@apollo/gateway` v0.x was officially deprecated as of 15 November 2022 and reached end-of-life on 22 September 2023. `@apollo/gateway` v2.x remains fully supported. |
| 10 | + |
| 11 | +[Learn more about deprecation and end-of-life.](https://www.apollographql.com/docs/resources/product-launch-stages#stages-for-discontinuing-support) |
| 12 | + |
| 13 | +## Do I need to modify my subgraph schemas to use Federation 2? |
| 14 | + |
| 15 | +Eventually. The process of [moving to Federation 2](/graphos/reference/migration/to-federation-version-2/) has three steps: |
| 16 | + |
| 17 | +1. Upgrade your gateway to support Federation 2 (we recommend [moving to the GraphOS Router](/graphos/reference/migration/from-gateway/)). |
| 18 | +2. Begin composing your supergraph schema with Federation 2 composition logic. |
| 19 | +3. Update your individual subgraphs to use Federation 2 features and directives. |
| 20 | + |
| 21 | +Steps 1 and 2 usually require no changes to your subgraph schemas. Schemas that do require changes are schemas that should cause certain composition errors that Federation 1 fails to detect ([see below.](#breaking-changes)). |
| 22 | + |
| 23 | +Step 3 does require some changes to your subgraph schemas, described [here](/graphos/reference/migration/to-federation-version-2/#step-3-update-individual-subgraphs). |
| 24 | + |
| 25 | + |
| 26 | +### Breaking changes |
| 27 | + |
| 28 | +As mentioned above, the following Federation 1 examples should produce composition errors, but they aren't detected. If your subgraph schemas include syntax that matches any of these, you need to update those schemas before moving to Federation 2. |
| 29 | + |
| 30 | +<ExpansionPanel title="See breaking changes"> |
| 31 | + |
| 32 | +#### Invalid `@key` directives |
| 33 | + |
| 34 | +An entity's `@key` consists of one or more of the entity's own `fields`. If any of these fields have subfields, the `@key` must also include at least one of those subfields: |
| 35 | + |
| 36 | +<p style="margin-bottom: 0">✅</p> |
| 37 | + |
| 38 | +```graphql {1} |
| 39 | +type User @key(fields: "id organization { id }") { |
| 40 | + id: ID! |
| 41 | + organization: Organization! |
| 42 | +} |
| 43 | + |
| 44 | +type Organization { |
| 45 | + id: ID! |
| 46 | + name: String! |
| 47 | +} |
| 48 | +``` |
| 49 | + |
| 50 | +In this example, the `User`'s key fields are `User.id` and `User.organization.id`. |
| 51 | + |
| 52 | +Federation 1 composition incorrectly allows a `@key` such as the following: |
| 53 | + |
| 54 | +<p style="margin-bottom: 0">❌</p> |
| 55 | + |
| 56 | +```graphql {1} |
| 57 | +type User @key(fields: "id organization") { |
| 58 | + id: ID! |
| 59 | + organization: Organization! |
| 60 | +} |
| 61 | + |
| 62 | +type Organization { |
| 63 | + id: ID! |
| 64 | + name: String! |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +This `@key` should break composition because it doesn't include at least one subfield of `Organization`. |
| 69 | + |
| 70 | +#### Invalid `@requires` directives |
| 71 | + |
| 72 | +A subgraph can mark an entity field with the [`@requires` directive](https://www.apollographql.com/docs/federation/entities/#extending-an-entity-with-computed-fields-advanced) to indicate that it depends on fields and subfields from another subgraph: |
| 73 | + |
| 74 | +<p style="margin-bottom: 0">✅</p> |
| 75 | + |
| 76 | +```graphql title="Subgraph A" |
| 77 | +type Product @key(fields:"sku") { |
| 78 | + sku: ID! |
| 79 | + dimensions: ProductDimensions! |
| 80 | +} |
| 81 | + |
| 82 | +type ProductDimensions { |
| 83 | + size: Int! |
| 84 | + weight: Int! |
| 85 | +} |
| 86 | +``` |
| 87 | + |
| 88 | +```graphql {4} title="Subgraph B" |
| 89 | +extend type Product @key(fields:"sku") { |
| 90 | + sku: ID! @external |
| 91 | + dimensions: ProductDimensions! @external |
| 92 | + shippingEstimate: Int! @requires(fields: "dimensions { size weight }") |
| 93 | +} |
| 94 | + |
| 95 | +type ProductDimensions { |
| 96 | + size: Int! |
| 97 | + weight: Int! |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +In this example, Subgraph B's `shippingEstimate` field depends on the `dimensions.size` and `dimensions.weight` fields of Subgraph A. |
| 102 | + |
| 103 | +Federation 1 incorrectly allows a `@requires` directive such as the following: |
| 104 | + |
| 105 | +<p style="margin-bottom: 0">❌</p> |
| 106 | + |
| 107 | +```graphql title="Subgraph A" |
| 108 | +type Product @key(fields:"sku") { |
| 109 | + sku: ID! |
| 110 | + dimensions: ProductDimensions! |
| 111 | +} |
| 112 | + |
| 113 | +type ProductDimensions { |
| 114 | + size: Int! |
| 115 | + weight: Int! |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +```graphql {4} title="Subgraph B" |
| 120 | +extend type Product @key(fields:"sku") { |
| 121 | + sku: ID! @external |
| 122 | + dimensions: ProductDimensions! @external |
| 123 | + shippingEstimate: Int! @requires(fields: "dimensions { length depth }") |
| 124 | +} |
| 125 | + |
| 126 | +type ProductDimensions { |
| 127 | + size: Int! |
| 128 | + weight: Int! |
| 129 | +} |
| 130 | +``` |
| 131 | + |
| 132 | +This `@requires` directive should break composition because it depends on subfields of `ProductDimensions` that don't exist (`length` and `depth`). |
| 133 | + |
| 134 | +#### Invalid `@provides` directives |
| 135 | + |
| 136 | +A subgraph can annotate an entity field with the [`@provides` directive](/federation/federated-types/federated-directives/#provides) to indicate that the subgraph can resolve entity fields normally marked as `@external` on its own. |
| 137 | + |
| 138 | +<p style="margin-bottom: 0">✅</p> |
| 139 | + |
| 140 | +```graphql title="Subgraph A" |
| 141 | +type Product @key(fields: "id") { |
| 142 | + id: ID! |
| 143 | + info: ProductInfo @external |
| 144 | +} |
| 145 | + |
| 146 | +type ProductInfo { |
| 147 | + name: String! @external |
| 148 | + inStock: Boolean! @external |
| 149 | +} |
| 150 | + |
| 151 | +type Query { |
| 152 | + outOfStockProducts: [Product!]! @provides(fields: "info { name }") |
| 153 | + discontinuedProducts: [Product!]! |
| 154 | +} |
| 155 | +``` |
| 156 | + |
| 157 | +In the above example, Subgraph A can resolve the `Product.info.name` field when accessed through the `outOfStockProducts` query. Any other path to `Product.info.name` results in an additional subgraph call. |
| 158 | + |
| 159 | +Federation 1 incorrectly allows `@provides` usage like the following: |
| 160 | + |
| 161 | +<p style="margin-bottom: 0">❌</p> |
| 162 | + |
| 163 | +```graphql title="Subgraph A" |
| 164 | +type Product @key(fields: "id") { |
| 165 | + id: ID! |
| 166 | + info: ProductInfo @external |
| 167 | +} |
| 168 | + |
| 169 | +type ProductInfo { |
| 170 | + name: String! @external |
| 171 | + inStock: Boolean! @external |
| 172 | +} |
| 173 | + |
| 174 | +type Query { |
| 175 | + outOfStockProducts: [Product!]! @provides(fields: "info") |
| 176 | + discontinuedProducts: [Product!]! |
| 177 | +} |
| 178 | +``` |
| 179 | + |
| 180 | +The above `@provides` directives usage should break composition because it does not specify which subfields of `ProductInfo` it can resolve. This is correctly caught and surfaced as an error in Federation v2 but Federation v1 incorrectly allows this usage. |
| 181 | + |
| 182 | +</ExpansionPanel> |
| 183 | + |
| 184 | + |
| 185 | +## Can Federation 1 compose my Federation 2 subgraph schemas? |
| 186 | + |
| 187 | +No, not after you [convert at least one subgraph schema](#do-i-need-to-modify-my-subgraph-schemas-to-use-federation-2) to a true Federation 2 schema. |
| 188 | + |
| 189 | +Federation 2 provides more flexible composition rules compared to Federation 1. After you modify your subgraph schemas to take advantage of this flexibility, your graph will no longer compose with Federation 1. You need to revert these changes to move back to Federation 1. |
| 190 | + |
| 191 | +## Does `@apollo/gateway` v2 support Federation 1? |
| 192 | + |
| 193 | +Yes. If you want, you can update your gateway's `@apollo/gateway` library to its latest `2.x` version before you're ready to [move your graph to Federation 2](/graphos/reference/migration/to-federation-version-2/). |
| 194 | + |
| 195 | +Your plugins and customizations for `@apollo/gateway` `0.x` will continue to work as expected in `@apollo/gateway` `2.x`. |
| 196 | + |
| 197 | +## Compatibility table |
| 198 | + |
| 199 | +| Router/Gateway version | Federation 1<br/>Composition | Federation 2<br/>Composition | |
| 200 | +|-|--------------|--------------| |
| 201 | +| Apollo Router Core v1.x | 🟢 | 🟢 | |
| 202 | +| `@apollo/gateway` v2.x | 🟢 | 🟢 | |
| 203 | +| `@apollo/gateway` v0.x (deprecated) | 🟢 | ❌ | |
0 commit comments