Odyssey

Intermediate Schema Design

IntroductionThe enum typeThe input typeInterfacesQuery fragments
5. Query fragments
4m

Overview

In the last lesson, we learned how to use interfaces to define common attributes that are shared across different types. We also learned how to write queries for those common attributes.

But what happens when we try to write queries for other fields that are unique to a particular implementing type? For example, in Airlock, the Review.author field returns an object that implements the User interface, which can either be a Host or a Guest. Hosts and guests have some fields that aren't shared with each other, like Host.listings or Guest.funds.

We know that a field that returns an interface can return any object type that implements that interface. So how do we know what other fields will be on that returned object?

To answer that, we'll need another GraphQL tool: query fragments.

In this lesson, we will:

  • Learn about inline and named fragments
  • Learn how to query interfaces and implement object types using both inline and named fragments

Querying an interface's shared fields

We can query a field that returns an interface in the same way we've queried other types and fields.

We start with the query keyword, then the name of our query, followed by curly braces. Inside the curly braces, we can query for the fields outlined in the interface.

Let's look at an example query from Airlock. This query uses the me operation, which returns the logged-in User. We'll also ask for the name and profilePicture fields, which are details that appear in Airlock's user profile page.

query GetMyProfile {
me {
name
profilePicture
}
}

The user profile page also shows additional information, depending on whether you're a host or a guest. For a host, we want to show their profile description. For guests, we want to show the current amount of funds they have in their wallet.

We can't add these fields right away to our query, because these fields belong to their specific Host or Guest type and the me field returns a User interface. If we tried to add the funds field to our existing query, we'd get an error, since the User interface doesn't have a funds field.

To query for the additional role-specific fields, we need to use a fragment.

GraphQL fragments

A GraphQL fragment is a subset of fields from an object type that you can reuse and share between multiple GraphQL operations.

Named fragments

To define a fragment, we start with the fragment keyword, then the name of the fragment (describing what it's for). Then, we add the keyword on, followed by the fragment's associated type. Inside the curly braces, we list the fields for that associated type.

fragment HostProfileFields on Host {
profileDescription
}
fragment GuestProfileFields on Guest {
funds
}

To use these fragments in our original query, we can include them in our field selection set. We do this by preceding the name of the fragment with three periods (...), similar to JavaScript's spread syntax.

query GetMyProfile {
me {
name
profilePicture
...HostProfileFields
...GuestProfileFields
}
}
fragment HostProfileFields on Host {
profileDescription
}
fragment GuestProfileFields on Guest {
funds
}

Note: You can test this query out in GraphOS Studio Sandbox in the next section.

These fragments are named fragments, and they're useful for reusing between different queries.

Inline fragments

We can also achieve a similar query output with inline fragments. For this, we replace the named fragment in our query with the contents of the fragment itself, keeping our three periods (...), and then specifying the type name (on Host or on Guest). This is handy when we don't need to reuse a fragment between operations.

With inline fragments, the query looks like this:

query GetMyProfile {
me {
name
profilePicture
... on Host {
profileDescription
}
... on Guest {
funds
}
}
}

Now if the logged-in user is a host, we fetch their profileDescription, and if the logged-in user is a guest, we fetch their funds. (And in all cases, we fetch the user's name, and profilePicture.)

Testing the query

To see these fragments in action, let's test out some queries using the Airlock GraphQL server.

Let's build the query to get the profile details using __typename and inline fragments.

query GetMyProfile {
me {
__typename
name
profilePicture
... on Host {
profileDescription
}
... on Guest {
funds
}
}
}

When we run this query from a client, it would be helpful to know what type of user we're getting back! We could check to see if the query results contain a profileDescription or funds, but this type of logic is brittle if the schema changes or we start needing more fields.

Instead, we can add another field to our query: __typename.

Every object type in your schema automatically has a field named __typename (you don't need to define it). The __typename field returns the object type's name as a String, which is useful for the client!

Now let's test out our query!

  1. Open a new browser window to http://localhost:4000, and click the button to query your server in GraphOS Studio Sandbox.

  2. Because Airlock requires authentication, we'll need to add an Authorization header in the Headers tab. Set the header value to either Bearer user-1 for a host or Bearer user-2 for a guest.

    Screenshot of GraphOS Studio Explorer. In the Headers tab, there's a header with a key called 'Authorization' and a value of 'Bearer user-1'.
  3. Copy the query above into the Explorer, and run it.

The response should look like one of following:

{
"data": {
"me": {
"__typename": "Host",
"name": "Eves",
"profilePicture": "https://res.cloudinary.com/apollographql/image/upload/odyssey/airlock/user-1.png",
"profileDescription": "I've been to 15 different planets and decided to make a home for myself and others in my favourites. Each planet and location has its own distinct environment, so read the description carefully. I have equipped them all with the necessary amenities!"
}
}
}
{
"data": {
"me": {
"__typename": "Guest",
"name": "Jackenn",
"profilePicture": "https://res.cloudinary.com/apollographql/image/upload/odyssey/airlock/user-2.png",
"funds": 37484 // this value may be different for you
}
}
}

We can also try out a similar query using named fragments (shown below). We'll get back the same data as the query with inline fragments!

query GetMyProfile {
me {
__typename
name
profilePicture
...HostProfileFields
...GuestProfileFields
}
}
fragment HostProfileFields on Host {
profileDescription
}
fragment GuestProfileFields on Guest {
funds
}

See it in the Airlock codebase

There are multiple query fragments used throughout the Airlock client code. Check out these examples:

  • The LISTING_FRAGMENT defined in client/src/utils.js
  • The inline fragments on Host and Guest in the GET_USER query defined in client/src/utils.js
  • The inline fragment on Host in the UPDATE_PROFILE mutation defined in client/src/pages/profile.js

Practice

Use the schema below to complete the next two code challenges:

type Query {
availableBooks: [Book]
borrowedBooks(userId: ID!): [Book]
}
interface Book {
isbn: ID!
title: String!
genre: String!
}
type PictureBook implements Book {
isbn: ID!
title: String!
genre: String!
numberOfPictures: Int
isInColor: Boolean
}
type YoungAdultNovel implements Book {
isbn: ID!
title: String!
genre: String!
wordCount: Int
numberOfChapters: Int
}
Code Challenge!

Complete the query below by declaring two named fragments. One is called PictureBookFields on the PictureBook type, retrieving fields for numberOfPictures and isInColor. Another is called YANovelFields on the YoungAdultNovel type, retrieving fields for wordCount and numberOfChapters. Use these named fragments in the GetAvailableBooks query.

Loading...
Loading initial values
Code Challenge!

Modify the query below to use inline fragments.

Loading...
Loading initial values

Key takeaways

  • A fragment is a subset of fields from an object type, usually used to share between multiple queries and mutations.
  • To query interfaces and their implementing types, we need to use either named or inline fragments.
    • Named fragments can stand alone and are great for reuse across multiple queries.
    • Inline fragments can be written and read easily within the query.

Conclusion

Well done, you've learned about four new GraphQL concepts that you can use when designing your own schemas!

If you're interested in digging deeper into the topics covered in this side quest, check out the list of additional resources below.

As for what's next, you can check out the Authentication & Authorization side quest, or dive into the Voyage series to learn how to modularize your graph using Apollo Federation.

Additional resources

  • Apollo Docs: GraphQL schema basics: More on enums and input types
  • Apollo Docs: Unions and interfaces
  • Apollo Docs: Fragments
  • GraphQL Docs: Schemas and Types: More on enums, input types, and interfaces
  • GraphQL Docs: Queries and Mutations: More on fragments
Previous
              attributes

              Key-value pairs that add contextual metadata to telemetry. The router supports a built-in set of standard attributes from OpenTelemetry semantic conventions, and custom selectors to extract data from the router request lifecycle.

              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
              }
              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
              }
              object type

              A type in a GraphQL schema that has one or more fields. User is an object type in the following example:

              type User {
              name: 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
              }
              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in data retrieval.

              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

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

              object types

              A type in a GraphQL schema that has one or more fields. User is an object type in the following example:

              type User {
              name: String!
              }
              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              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
              }
              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.

              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
              }
              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
              }
              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
              }
              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
              }
              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in 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
              }
              object type

              A type in a GraphQL schema that has one or more fields. User is an object type in the following example:

              type User {
              name: String!
              }
              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in data retrieval.

              operations

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

              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              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
              }
              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              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
              }
              selection set

              The part of a GraphQL query that specifies the fields and subfields to retrieve from the server. Selection sets define the structure and shape of the data response.

              The following example query has four selection sets:

              query GetWeatherForecast {
              weatherForecast {
              currentConditions {
              conditions
              temperature
              }
              dailyForecast {
              highTemperature
              lowTemperature
              conditions
              }
              timestamp
              }
              }

              The root selection set contains the weatherForecast field. weatherForecast has its own selection set with three fields. Two of those fields—currentConditions and dailyForecast— contain selection sets themselves.

              query

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

              GraphOS Studio

              The web interface for GraphOS, which provides graph, variant, and organization management, metrics visualization, schema pipeline tools and more.

              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

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

              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

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

              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              operations

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

              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

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

              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              GraphQL server

              A server that contains a GraphQL schema and can resolve client-requested operations that are executed against that schema.

              query

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

              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

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

              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.

              object type

              A type in a GraphQL schema that has one or more fields. User is an object type in the following example:

              type User {
              name: 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
              }
              object type

              A type in a GraphQL schema that has one or more fields. User is an object type in the following example:

              type User {
              name: String!
              }
              query

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

              query

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

              GraphOS Studio

              The web interface for GraphOS, which provides graph, variant, and organization management, metrics visualization, schema pipeline tools and more.

              query

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

              query

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

              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

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

              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

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

              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              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
              }
              object type

              A type in a GraphQL schema that has one or more fields. User is an object type in the following example:

              type User {
              name: String!
              }
              mutations

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              query

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

              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

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

              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in data retrieval.

              graph

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

              Apollo Federation

              Apollo’s implementation of GraphQL Federation—an architecture for orchestrating multiple APIs into a single GraphQL API.

              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }

              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