8. Composition check errors
10m

Overview

We've seen how schema checks and launches work in our development flow and what happens when the process goes smoothly without any errors. It's time to tackle what happens in the not-so-happy path, when changes to a subgraph result in composition errors.

In this lesson, we will:

  • Learn about the types of errors commonly encountered in supergraph composition
  • Learn how to navigate composition errors in Studio
  • Learn how to use the @inaccessible directive

Updating the subgraph

Let's return to our subgraph teams, who are hard at work improving Airlock. 👩🏽‍🚀 Achilles from the Accounts team has just made a few changes to the accounts subgraph's schema to bring visibility into a host's galactic coordinates.

In the schema, they've defined the GalacticCoordinates type the team has agreed on and included the two fields: latitude and longitude.

subgraph-accounts/accounts.graphql
type GalacticCoordinates {
latitude: Float!
longitude: Float!
}

(Did you spot the mistake already? Don't worry, we'll get to that in a moment! Remember, this lesson is about what happens when things don't work the first time!)

They've also added a new field to the Host entity: coordinates, which returns the GalacticCoordinates type.

subgraph-accounts/accounts.graphql
type Host implements User @key(fields: "id") {
#... other Host fields
"Where the host is primarily located"
coordinates: GalacticCoordinates
}

With these new schema additions in place, we're ready to help Achilles publish the changes and get this feature out into the world. Following the process we walked through in the previous lesson, the first thing on the list is using Rover to run a local schema check.

We'll open up a new terminal window and run the rover subgraph check command against Airlock's staging variant, including the file path and subgraph name parameters for the accounts schema.

rover subgraph check airlock-managed-fed@staging \
--schema "accounts.graphql" \
--name accounts

Right away, we see that something isn't quite right! Here's the error message we see in the terminal:

Checking the proposed schema for subgraph accounts against airlock-managed-fed@staging
error[E029]: Encountered 2 build errors while trying to build subgraph "accounts" into supergraph "airlock-managed-fed@staging".
Caused by:
Encountered 2 build errors while trying to build the supergraph.
INVALID_FIELD_SHARING: Non-shareable field "GalacticCoordinates.latitude" is resolved from multiple subgraphs: it is resolved from subgraphs "accounts" and "listings" and defined as non-shareable in subgraph "accounts"
INVALID_FIELD_SHARING: Non-shareable field "GalacticCoordinates.longitude" is resolved from multiple subgraphs: it is resolved from subgraphs "accounts" and "listings" and defined as non-shareable in subgraph "accounts"
The changes in the schema you proposed for subgraph accounts are incompatible with supergraph airlock-managed-fed@staging. See https://www.apollographql.com/docs/federation/errors/ for more information on resolving build errors.

The errors indicate that the GalacticCoordinates fields (latitude and longitude) are resolved in both the accounts and listings subgraphs, but they're defined as non-shareable in the accounts subgraph. That's the subgraph Achilles was working on!

What they missed was adding the @shareable directive to the type definition, so let's make sure that's included.

subgraph-accounts/accounts.graphql
type GalacticCoordinates @shareable {
latitude: Float!
longitude: Float!
}

Achilles makes the update to their schema, and when we run the rover subgraph check command again, we can see that this fix has resolved the composition error!

Checking the proposed schema for subgraph accounts against airlock-managed-fed@staging
Check Result:
Compared 1 schema changes against 13 operations
┌────────┬─────────────┬───────────────────────────────────────────────┐
│ Change │ Code │ Description │
├────────┼─────────────┼───────────────────────────────────────────────┤
│ PASS │ FIELD_ADDED │ type `Host`: field `coordinates` added │
└────────┴─────────────┴───────────────────────────────────────────────┘
View full details at https://studio.apollographql.com/graph/airlock-managed-fed/operationsCheck/{URL}

Achilles continues to work on their subgraph, adding the necessary resolvers and data source methods to implement their schema additions.

Adding new shared fields

Before pushing their changes up to the codebase, Achilles meets with the Airlock team and finds out that the project mockup designs have been updated! In addition to the numerical coordinates, users also want to know the local name of the location. For example, it's easier for guests to immediately understand "Planet Z" compared to "83.0405 latitude and 35.2034 longitude" (but they'll still also need to know the precise coordinates).

Achilles adds a new field to the GalacticCoordinates type: nickname, which returns a String.

subgraph-accounts/accounts.graphql
type GalacticCoordinates @shareable {
latitude: Float!
longitude: Float!
nickname: String
}

Awesome! This new field is already being returned by the AccountsAPI service, so there are no additional changes to be made in the resolvers or data source files. Achilles is so excited to get this feature out, they forget to rerun the rover subgraph check command locally again. Instead, they push the change straight up to the GitHub codebase and create a PR. This triggers the Schema Checks job.

Oh no, the job failed!

https://github.com
Screenshot of the GitHub PR with the job failed and link to the Studio Checks page

Not to worry, that means our pipeline caught an error before it made it to production! We can investigate exactly why the job failed by following the link to Apollo Studio's Checks page embedded in the PR.

Schema checks in Apollo Studio

The Checks page in Studio shows us the results of the schema check so we can diagnose what went wrong.

https://studio.apollographql.com
Screenshot of the failed check in Studio Checks page

Studio identifies the subgraph that failed to compose and indicates what went wrong in the process. And because failing composition means no new supergraph schema is generated, the router continues to process requests based on its existing valid version of the supergraph schema. So even though the Accounts team's changes aren't working, clients using the staging variant of the graph don't encounter any errors! This gives the Accounts team a chance to review the error and push a fix before merging their PR.

This is the error we see:

error[E029]: Encountered 1 build error while trying to build subgraph "accounts" into supergraph "airlock-managed-fed@staging".
Caused by:
Encountered 1 build error while trying to build the supergraph.
SATISFIABILITY_ERROR: The following supergraph API query:
mutation {
updateListing(listingId: "<any id>", listing: {}) {
listing {
coordinates {
nickname
}
}
}
}
cannot be satisfied by the subgraphs because:
- from subgraph "listings":
- cannot find field "GalacticCoordinates.nickname".
- cannot move to subgraph "accounts", which has field "GalacticCoordinates.nickname", because type "GalacticCoordinates" has no @key defined in subgraph "accounts".

Let's investigate the error further.

When trying to build the supergraph schema, we ran into a SATISFIABILITY_ERROR. This error means that our subgraphs might appear compatible on the surface, but the resulting supergraph API would include at least one operation that the subgraphs can't satisfy.

The error message provides an example operation, along with two reasons why our subgraphs can't satisfy it:

First, the listings subgraph can't find the field GalacticCoordinates.nickname. Achilles had only added the nickname field to the accounts subgraph (the subgraph their team is responsible for). The listings subgraph has no such field.

Second, the listings subgraph can't pass the responsibility of resolving the nickname field to the accounts subgraph, because GalacticCoordinates isn't an entity, it's a value type. Remember that only entities (types with the @key directive) can resolve different fields across multiple subgraphs.

The fields of a value type can differ across subgraphs in some ways, but we can't omit shared fields. We need to add this new GalacticCoordinates.nickname field to both the accounts and listings subgraphs.

Note: You can learn more about the different ways shared fields can differ in value types in the Apollo docs on sharing types.

To incrementally add the field to all of our subgraphs without breaking composition, we can use the @inaccessible directive.

The @inaccessible directive

The @inaccessible directive is applied to a field in a subgraph schema. Whenever it's present on a field, composition omits that field from the router's API schema. This means that clients can't include the field in operations. This helps us incrementally add a field to multiple subgraphs without breaking composition.

Note that we only need to apply the @inaccessible directive to one of the subgraphs where the field is defined.

Let's use the @inaccessible directive to incrementally add the nickname field to the GalacticCoordinates value type. Here's the plan:

👩🏽‍🚀 In the accounts subgraph:

  • Achilles will add the GalacticCoordinates.nickname field and apply the @inaccessible directive.
  • We'll use our automated CI/CD process to ensure these schema additions make their way to the staging variant in the registry.

👩🏽‍🏫 Then, in the listings subgraph:

  • Lisa will add the GalacticCoordinates.nickname field. We don't need to apply @inaccessible because it's already taken care of in the accounts subgraph.
  • We'll use our automated CI/CD process to ensure these schema additions make their way to the staging variant in the registry.

👩🏽‍🚀 With the new shared field added to all the subgraphs that use the value type, we can finally go back to the accounts subgraph:

  • Achilles will remove the @inaccessible directive from the GalacticCoordinates.nickname field. This allows the field to be included in the composition and compose successfully, because the listings subgraph now includes the nickname field.
  • We'll use our automated CI/CD process to ensure these schema additions make their way to the staging variant in the registry.

Let's get to it!

Using the @inaccessible directive

👩🏽‍🚀 In the accounts subgraph, Achilles will add the @inaccessible directive after the return type of the nickname field.

subgraph-accounts/accounts.graphql
type GalacticCoordinates @shareable {
latitude: Float!
longitude: Float!
nickname: String @inaccessible
}

Achilles also needs to make sure the directive is included in the import array at the top of the schema.

subgraph-accounts/accounts.graphql
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0"
import: ["@key", "@shareable", "@inaccessible"])

And that's it! With these schema changes in place, let's try running a local schema check.

rover subgraph check airlock-managed-fed@staging \
--schema "./accounts.graphql" \
--name accounts

In the terminal, we'll see:

Checking the proposed schema for subgraph accounts against airlock-managed-fed@staging
Compared 1 schema changes against 16 operations
┌────────┬─────────────┬────────────────────────────────────────┐
│ Change │ Code │ Description │
├────────┼─────────────┼────────────────────────────────────────┤
│ PASS │ FIELD_ADDED │ type `Host`: field `coordinates` added │
└────────┴─────────────┴────────────────────────────────────────┘

Awesome, the checks pass with no errors! The addition of the nickname field doesn't show up in the check because it's currently marked as @inaccessible. We'll push the changes up to GitHub and let the CI run its schema checks as well. When those pass, we can merge the PR, automatically triggering the deploy process to deploy the changes to the accounts subgraph staging environment in Heroku and the Airlock graph staging variant in the Apollo schema registry.

Adding the new shared field to the listings subgraph

👩🏽‍🏫 Back over to the listings subgraph, Lisa will add the nickname field to the GalacticCoordinates value type.

subgraph-listings/listings.graphql
type GalacticCoordinates @shareable {
latitude: Float!
longitude: Float!
nickname: String
}

This new field is already being returned by the ListingsAPI service, so there are no additional changes to be made in the resolvers or data source files. We can follow the CI/CD process and get these schema changes up on the listings subgraph staging environment in Heroku and the Airlock graph staging variant in the Apollo schema registry!

Removing the @inaccessible directive

👩🏽‍🚀 With the GalacticCoordinates.nickname field defined in every subgraph that uses the value type, Achilles is ready to remove the @inaccessible directive from the GalacticCoordinates.nickname field.

subgraph-accounts/accounts.graphql
type GalacticCoordinates @shareable {
latitude: Float!
longitude: Float!
nickname: String
}

That's it! We can follow the same CI/CD process we're used to by now and get these schema changes up on staging!

This time the schema check will show that the nickname field was successfully added:

Checking the proposed schema for subgraph accounts against airlock-managed-fed@staging
Compared 1 schema changes against 16 operations
┌────────┬─────────────┬────────────────────────────────────────────────────┐
│ Change │ Code │ Description │
├────────┼─────────────┼────────────────────────────────────────────────────┤
│ PASS │ FIELD_ADDED │ type `GalacticCoordinates`: field `nickname` added │
└────────┴─────────────┴────────────────────────────────────────────────────┘

After we've validated that everything in the staging environment looks good, we're ready to deploy to production! We've already gone over those steps in the previous lesson, so feel free to refer to that section if you need a refresher.

We've improved on our Project Galactic Coordinates by adding a familiar nickname to the coordinates. This feature is officially out in the world and ready to be used by clients!

Practice

Which of the following statements about composition checks are true?

Key takeaways

  • We use the rover subgraph check command to perform schema checks locally.
  • The output of schema checks can be viewed in Studio, as well as locally with the Rover CLI.
  • To add a new shared field to a value type, we should first apply the @inaccessible directive to the field. Then, we can incrementally add the new field to each subgraph that defines the value type. Finally, we can remove the @inaccessible directive and the field will be officially part of the supergraph schema.

Up next

In the next lesson, we'll learn about operation checks, and how Studio validates proposed schema changes against the way clients have historically consumed data from the graph.

Previous
Next