Odyssey

Lift-off V: Production & the Schema Registry
deprecated

Overview & SetupWhat is the schema registry?Registering our schemaDeploying Apollo ServerDeploying Apollo ClientField deprecationSchema changes in the registryMonitoring and scaling our API
7. Schema changes in the registry
3m

🙌🏽 Checking out the registry

Our API changes have been deployed to production, so let's have a look at the Apollo schema registry.

The Changelog page

Go to your deployed graph in Apollo Studio, and click on the Changelog page in the left sidebar. This page shows every update made to our schema, presented in a "diff"-like format that may feel familiar: green pluses for additions, red minuses for deletions, and yellow circles for modifications from previous versions. Pretty handy to get a quick understanding of the schema evolution over time!

https://studio.apollographql.com
Screenshot of the changelog page in Apollo Studio, showing fields that have been added, removed and modified

We can see a new schema version published today with the commit hash, showing how many types and fields were added, removed, and modified. These were the exact changes we made earlier, now available for other members of our organization to see!

The items displayed in the Changelog are interactive. For example, when we click on the durationInSeconds field we just added, we're sent to the Reference tab of the Schema page, where we get a breakdown of our schema's entry points, objects, scalars, and more.

https://studio.apollographql.com
Screenshot of the Schema Reference page, highlighting the `durationInSeconds` field

Building a new test query

Let's use the Explorer to build a new query so that we can try out our updated track and module fields specifically on our deployed production graph.

We'll name our query GetTrackAndModuleDurations and add the track field through the sidebar. We can see here that the length field is now greyed out with a little warning icon that shows our deprecation message.

https://studio.apollographql.com
Screenshot of Explorer showing the deprecated length field

We can still add a deprecated field to our query, but the deprecation warning will always be there to remind us that we should use the new field instead.

Let's add the new durationInSeconds field. For this track, we'll also query for its list of modules, and the length and durationInSeconds fields. We can see the length field for a module has also been deprecated.

query GetTrackAndModuleDurations($trackId: ID!) {
track(id: $trackId) {
length
durationInSeconds
modules {
length
durationInSeconds
}
}
}

Before running the query, let's make sure to give the trackId variable our favourite value, c_0. Add the following to the Variables panel:

{
"trackId": "c_0"
}

After running the query, we can see in the response that both fields are resolved successfully with the same value!

https://studio.apollographql.com
Screenshot of the successful response to the GetTrackAndModuleDurations query in Explorer
Which of these are true about a field that has been assigned the @deprecated directive?

Our schema is updated, but we're not quite done with our plan! Step 3 was to monitor usage for the old field, before we can move on to step 4, removing the old field completely. We can use the registry to track API state and usage down to the field level.

📉 Field usage

Let's hop over to the Fields page and explore the current state of our schema, with all of its types and fields. For each field, we can see two metrics that have been measured for our graph in the last day: field executions and referencing operations.

https://studio.apollographql.com
The Fields page displaying field executions and referencing operations for each field

The number of field executions represents how many times the server has executed the resolver function for a specific field over the given period.

Referencing operations, on the other hand, lists the number of operations in a given period that have included the particular field.

Note: By default, this period is set to the last day, but we can customize the range by toggling the filter at the top of the page.

The number of field executions and the number of referencing operations can differ considerably, depending on which operations are being sent, and how many times the field is resolved as part of each operation.

In our case, let's look at the deprecated Module.length field. We can use the following query to visualize how the number of field executions and referencing operations might differ for this particular field.

query GetTrackModuleLengths($trackId: ID!) {
track(id: $trackId) {
modules {
length
}
}
}

In this query, we have an operation called GetTrackModuleLengths, which requests a specific Track based on the trackId it receives as an argument. For this particular Track object, we are requesting the modules field, which resolves to a list of Module objects.

Because this can return more than one Module object, our operation will potentially execute the length resolver function multiple times, as shown in the following example response.

{
"data": {
"track": {
"modules": [
{
"length": 258
},
{
"length": 164
},
{
"length": 481
},
{
"length": 144
},
{
"length": 203
},
{
"length": 309
},
{
"length": 304
},
{
"length": 137
},
{
"length": 140
},
{
"length": 237
}
]
}
}
}

In this example, for the Module.length field, we'll have one referencing operation (GetTrackModuleLengths) but multiple field executions.

Addressing deprecated fields

We can see from the field metrics on the Fields page that our deprecated length field is still being used.

https://studio.apollographql.com
Screenshot of the field usage for the `length` field in our schema

We want to make sure that usage for this field goes down to zero. To do so, we'll need to make a few changes to our client app, replacing all the occurrences of length with durationInSeconds. Then we commit, push and deploy.

Note: We'll leave these changes to the client app as an exercise for you! Make sure to test your changes locally before deploying to production.

After those changes to the client are made, our API change will be fully rolled out on both server and client side!

From the trainee catstronaut's perspective, everything should be working the same as before. But behind the scenes, we're using the new field.

Replacing a field
When replacing a field in your schema, there are a number of steps you should follow. First, 
 
 to your schema. Next, 
 
 by using the 
 
. Then, make sure to 
 
, waiting until usage of that field goes down before we can 
 
.

Drag items from this box to the blanks above

  • deprecate the old field

  • rename the old field

  • @replacement directive

  • add the new replacement field

  • monitor usage of the old field

  • monitor usage of the new field

  • remove the old field

  • @deprecated directive

To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.

Kudos for making our API a little better 🎉! We now have a good understanding of the steps to modify and improve it over time. In the final lesson, we'll explore how to keep our fingers on the pulse of our API and where we can take it from there.

Previous
Next

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.

              graph

              A schema-based data model representing how different data elements interconnect and can be accessed.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              scalars

              A "base" type that resolves to a single value. GraphQL includes the following scalar types by default: Int, Float, String, Boolean, and ID.

              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              graph

              A schema-based data model representing how different data elements interconnect and can be accessed.

              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              variable

              A placeholder for dynamic values in an operation allowing parameterization and reusability in requests. Variables can be used to fill arguments or passed to directives.

              query GetUser($userId: ID!) {
              user(id: $userId) {
              firstName
              }
              }

              In the query above, userId is a variable. The variable and its type are declared in the operation signature, signified by a $. The type of variable is a non-nullable ID. A variable's type must match the type of any argument it's used for.

              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              metrics

              Measurements of the router's behavior that can be exported and monitored, for example, the number of in-flight requests.

              graph

              A schema-based data model representing how different data elements interconnect and can be accessed.

              operations

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              resolver

              A function that populates data for a particular field in a GraphQL schema. For example:

              const resolvers = {
              Query: {
              author(root, args, context, info) {
              return find(authors, { id: args.id });
              },
              },
              };
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              operations

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              operations

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              operations

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              argument

              A key-value pair associated with a particular schema field that lets operations pass data to that field's resolver.

              Argument values can be hardcoded as literal values (shown below for clarity) or provided via GraphQL variables (recommended).

              query GetHuman {
              human(id: "200") {
              name
              height(unit: "meters")
              }
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              resolver

              A function that populates data for a particular field in a GraphQL schema. For example:

              const resolvers = {
              Query: {
              author(root, args, context, info) {
              return find(authors, { id: args.id });
              },
              },
              };
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              metrics

              Measurements of the router's behavior that can be exported and monitored, for example, the number of in-flight requests.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }

              NEW COURSE ALERT

              Introducing Apollo Connectors

              Connectors are the new and easy way to get started with GraphQL, using existing REST APIs.

              Say goodbye to GraphQL servers and resolvers—now, everything happens in the schema!

              Take the course