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.
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.
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@stagingerror[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.
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@stagingCheck 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
.
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!
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 Studio's Checks page embedded in the PR.
Schema checks in GraphOS
The Checks page in Studio shows us the results of the schema check so we can diagnose what went wrong.
GraphOS 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 GraphOS 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 theaccounts
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 theGalacticCoordinates.nickname
field. This allows the field to be included in the composition and compose successfully, because thelistings
subgraph now includes thenickname
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.
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.
extend schema@link(url: "https://specs.apollo.dev/federation/v2.7"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@stagingCompared 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.
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.
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@stagingCompared 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
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 GraphOS validates proposed schema changes against the way clients have historically consumed data from the graph.
Share your questions and comments about this lesson
Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.
You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.