Skip to content

Commit

Permalink
Clarify fed2 composition rules for enums (#2011)
Browse files Browse the repository at this point in the history
* Clarify fed2 composition rules for enums

* Update docs/source/federated-types/composition.mdx

Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>

* Update docs/source/federated-types/composition.mdx

Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>

* Update docs/source/federated-types/composition.mdx

Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>

Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>
  • Loading branch information
Stephen Barlow and rkoron007 committed Jul 26, 2022
1 parent f9a1734 commit 4275648
Showing 1 changed file with 66 additions and 46 deletions.
112 changes: 66 additions & 46 deletions docs/source/federated-types/composition.mdx
Expand Up @@ -365,18 +365,21 @@ As you can see, the supergraph schema includes only the input fields and argumen

### Enums

Composition might use the union strategy _or_ the intersection strategy when merging enum type definitions, _depending on how the enum is used_.
If an enum definition differs between subgraphs, the [composition strategy](#merging-types-from-multiple-subgraphs) depends on how the enum is used:

```mermaid
graph TB;
enum("Is the enum used as the type for at least<br/>one field argument or input type field?");
enum--No-->union("Union");
enum--Yes-->intersection("Intersection");
```
| Scenario | Strategy |
|----------|----------|
| The enum is used as the return type for at least one object or interface field. | [Union](#union) |
| The enum is used as the type for at least one field argument or input type field. | [Intersection](#intersection) |
| **Both** of the above are true. | All definitions must [match **exactly**](#exact-match) |

If your enum is **not** used as the type of a field argument or input type field, then composition merges using the [union strategy](#merging-types-from-multiple-subgraphs).
Examples of these scenarios are provided below.

Consider the following subgraph schemas:
#### Enum composition examples

##### Union

Consider these subgraph schemas:

<CodeColumns>

Expand All @@ -386,35 +389,44 @@ enum Color {
GREEN
BLUE
}

type Query {
favoriteColor: Color
}
```

```graphql title="Subgraph B"
enum Color {
RED
CYAN
MAGENTA
GREEN
YELLOW
}

type Query {
currentColor: Color
}
```

</CodeColumns>

When these subgraph schemas are composed, composition merges the `Color` enum by union. This results in the following type definition in the supergraph schema:
In this case, the `Color` enum is used as the return type of at least one object field. Therefore, composition merges the `Color` enum by union, so that all possible subgraph return values are valid.

This results in the following type definition in the supergraph schema:

```graphql title="Supergraph schema"
enum Color {
RED
GREEN
BLUE
CYAN
MAGENTA
YELLOW
}
```

If you use an enum as _either_ a field argument or an input field's return type in at least one of your subgraphs, composition merges using the [intersection strategy](#merging-types-from-multiple-subgraphs).
##### Intersection

Consider these subgraph schemas:

Let's say we add a new field to Subgraph A that uses our `Color` enum as a field argument:
<CodeColumns>

```graphql title="Subgraph A"
enum Color {
Expand All @@ -423,24 +435,42 @@ enum Color {
BLUE
}

type ColorQuery {
avatar(borderColor: Color): String
type Query {
products(color: Color): [Product]
}
```

Now when composition runs, the `Color` enum is merged by _intersection_:

```graphql title="Supergraph schema"
```graphql title="Subgraph B"
enum Color {
RED
GREEN
YELLOW
}

type ColorQuery {
avatar(borderColor: Color): String
type Query {
images(color: Color): [Image]
}
```

</CodeColumns>

In this case, the `Color` enum is used as the type of at least one field argument (or input type field). Therefore, composition merges the `Color` enum by intersection, so that subgraphs never receive a client-provided enum value that they don't support.

This results in the following type definition in the supergraph schema:

```graphql title="Supergraph schema"
# BLUE and YELLOW are removed via intersection
enum Color {
RED
GREEN
}
```

If you are using an enum as either a field argument or an input field return type and you want to include _all_ of its values in the supergraph schema, ensure _every_ subgraph's type definition for that enum is identical:
##### Exact match

Consider these subgraph schemas:

<p style="margin-bottom: 0">❌</p>

<CodeColumns>

Expand All @@ -449,42 +479,32 @@ enum Color {
RED
GREEN
BLUE
CYAN
MAGENTA
YELLOW
}

type ColorQuery {
avatar(borderColor: Color): String
type Query {
favoriteColor: Color
}
```

```graphql title="Subgraph B"
enum Color {
RED
GREEN
BLUE
CYAN
MAGENTA
YELLOW
}

type Query {
images(color: Color): [Image]
}
```

</CodeColumns>

This results in the following type definition in the supergraph schema:
In this case, the `Color` enum is used as _both_:

```js title="Supergraph Schema"
enum Color {
RED
GREEN
BLUE
CYAN
MAGENTA
YELLOW
}
* The return type of at least one object field
* The type of at least one field argument (or input type field)

type ColorQuery {
avatar(borderColor: Color): String
}
```
Therefore, the definition of the `Color` enum **must match exactly** in every subgraph that defines it. An exact match is the only scenario that enables union _and_ intersection to produce the same result.

The subgraph schemas above _do not compose_, because their definitions of the `Color` enum differ.

0 comments on commit 4275648

Please sign in to comment.