3. Field deprecation
5m

Overview

Let's begin with the first change we want to make to our .

In this lesson, we will:

  • Learn the process for replacing a in our schema
  • Learn what a is used for
  • Use the @deprecated for a in our schema

The schema so far

A common situation for an evolving is to deprecate an existing in the schema in favor of a new field. Let's investigate one such situation in our Poetic Plates .

Here's what the schema looks like for the Ingredient type:

type Ingredient {
id: ID!
"Display text for the ingredient"
text: String
"The name of an ingredient"
name: String
"A potential substitute for the ingredient, if available"
substitute: String
}

Users have shared feedback about their confusion related to the text and name of an ingredient.

Let's take a look at what values those return. Using your 's Explorer, run the following to retrieve the list of ingredients for a random recipe.

query GetRandomRecipeIngredients {
randomRecipe {
ingredients {
text
name
}
}
}

Depending on which recipe you received randomly, your response may be different, but here's a snippet of what we received:

{
"data": {
"randomRecipe": {
"ingredients": [
{ "text": "1 cup onions, medium diced", "name": "onions" },
{ "text": "2 tbsp olive oil", "name": "olive oil" }
// ...
]
}
}
}

Can you see the difference between text and name?

It looks like the text returns a longer, more detailed version about the ingredient. The name simply returns what the ingredient is, without any additional details like quantity or how it's prepared.

Digging deeper into each 's description in the schema, it isn't clear from the documentation that this is what users should expect. So we can definitely understand the confusion about which field they should be using for their purposes.

We should fix the description in the schema so that it's more clear what each is expected to return. We can also improve our schema to be more explicit about what exactly the text returns. Maybe there's a better name for this !

This requires changes to our schema, but we don't want to remove the text and replace it with a new one all in one go. That would break existing queries clients are sending, and we don't want to alarm anyone!

So here's the plan:

  1. Add a new to the schema.
  2. Mark the old as deprecated.
  3. Monitor usage of the old .
  4. Whenever usage is down and clients have had appropriate time to make their changes, we can safely remove the old !

Let's get to it!

Adding a new field to the schema

First, let's add the new to our schema.

  1. Open up the recipes repostiory in your code editor and navigate to the schema.graphql file.

  2. Find the Ingredient type, and add a new called detailedDescription. This name is much clearer than text! This returns a String type, and we'll also give it an accurate description, complete with an example.

    schema.graphql
    """
    A detailed description of the ingredient needed in the recipe.
    Usually in the format of: <QUANTITY> <INGREDIENT NAME>, <SPECIAL INSTRUCTIONS>.
    For example: 1 cup onions, medium diced
    """
    detailedDescription: String

Adding a new resolver

We'll need a for this new . Our doesn't provide this detailedDescription property. That's okay—it doesn't need to match our schema's 1 to 1. That's the beauty of !

  1. Open up the src/resolvers/Ingredient.js file.

  2. Add a new property under the Ingredient object with the same name as the , detailedDescription. This will be set to our function.

    src/resolvers/Ingredient.js
    module.exports = {
    Ingredient: {
    detailedDescription: () => {},
    },
    };

    Remember, this will be the exact same value as the text . So we'll want to take that text value and return it from the detailedDescription .

    We can access the text value using the first parameter of the , the parent, because of the chain.

  3. In the detailedDescription , we'll destructure the first parameter (parent) for the text property. We don't need any of the other parameters, and we'll return that text value right away in the body of the .

    src/resolvers/Ingredient.js
    detailedDescription: ({ text }) => text,

    That's our new taken care of!

Testing our changes

Let's make sure that the new schema addition is working properly.

If your server isn't running, you can start it with npm run dev. This will start the server at http://localhost:4001. Let's head over there in the browser to test out a with Sandbox.

We should see the new detailedDescription show up on the Documentation panel on the left.

Let's try this that retrieves a random recipe and its ingredients: both the text and detailedDescription .

query GetRandomRecipeIngredients {
randomRecipe {
ingredients {
text
detailedDescription
}
}
}

When we get data back, we should see that the values for both the text and detailedDescription are the same.

Everything's working as expected! Onwards with our plan, we need to mark the text as deprecated.

The @deprecated directive

For our use case, we'll use one of 's default : @deprecated.

Illustration showing the syntax for the deprecated directive in a schema

We apply the @deprecated to a to indicate that the field is... deprecated! We should always pass this directive a reason , which indicates why it's being deprecated, and which a client should use instead. This is useful information for the clients your .

Illustration showing the syntax for using the deprecated directive in the schema with the reason argument

Using the @deprecated directive

  1. Open up the schema.graphql file again.

  2. Find the Ingredient type's text . After the return type of the text , we'll add the @deprecated , with the reason as "Use detailedDescription".

    The Ingredient.text should now look like this:

    schema.graphql
    "Display text for the ingredient"
    text: String @deprecated(reason: "Use detailedDescription")

And there we go!

Testing our changes

So what's changed? Let's find out! Your server should still be running and pulling the latest changes (if not, make sure you run npm run dev again). Head back over to http://localhost:4001.

Looking at the same we had earlier, we can now see a couple changes!

http://localhost:4001

Sandbox Explorer showing a deprecated message for the text field

First, the text is showing up with a yellow squiggly underline, and if we hover over it, we'll see why! The field is deprecated, just like we marked in our schema. We can also see the same message on the Documentation panel on the left.

We can still run the with no issues, but the warning is meant to let us know that we really shouldn't be including the text in our queries anymore.

Practice

Schema Directives
A schema directive starts with the 
 
 character and it can appear after particular symbols in the schema, such as
 
 or
 
. An example of a default directive is
 
, which indicates that a field should no longer be used. This directive is often used with the 
 
 argument to specify why the field shouldn't be used, or which field to use instead.

Drag items from this box to the blanks above

  • @deprecated

  • resolvers

  • description

  • fields

  • reason

  • @

  • types

  • @deleted

  • message

  • !

What are some steps we should take before removing a field from the schema?

Key takeaways

  • To replace a in our schema, we should:
    • Add the new
    • Mark the old as deprecated
    • Monitor usage of the old
    • Whenever usage is down and clients have had appropriate time to make their changes, we can safely remove the old !
  • A schema directive is indicated with an @ character, and it decorates a specific symbol in your schema, such as a type or definition.
  • To deprecate a , we use the default @deprecated and the reason to let our consumers know why and which to use instead.
  • We can still run queries with deprecated , but the deprecation status is a cue for us to stop using that field in existing queries.

Up next

We've completed the first two steps of our plan, but that was all in our local environment. We need to let know about these changes!

In the next two lessons, we'll take a look at how we can land these changes safely and confidently using and .

Previous

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.