12. Adding the Amenity type
10m

Overview

We're close to finishing up the data needed for the listing details page. Let's go ahead and add the amenities!

In this lesson, we will:

  • Introduce the Amenity type to our schema
  • Build queries to display data for a listing and all of its amenities

Building the Amenity type

As we learned in the lesson on syntax, on types don't have to return a basic type—they can also return other !

For instance, we can give our Listing type an amenities —but what does this field actually return?

A screenshot of Airlock, focused on a particular listing's amenities

type Listing {
id: ID!
title: String!
description: String!
numOfBeds: Int!
costPerNight: Float!
closedForBookings: Boolean
amenities: # What type should this be?
}

Putting our business glasses on, we can see how more detailed data about an amenity—such as its id, name, what category it belongs to—would come in handy. The better or more descriptive the amenities a listing has to offer, the more motivated users might feel to make a booking! Furthermore, several listings might have the same kind of amenities; unlike an id or a title, a listing's amenities might not be unique to the listing itself!

For these reasons, we need to think of an "amenity" as a standalone —in other words, we should make it its own type called Amenity.

This means that our Listing type should be updated: we need its amenities to return a list of Amenity types!

Update your Listing type with the amenities description and highlighted below.

type Listing {
id: ID!
title: String!
description: String!
numOfBeds: Int!
costPerNight: Float!
closedForBookings: Boolean
"The amenities available for this listing"
amenities: [Amenity!]!
}

Now, let's actually define what an Amenity looks like. From our REST API responses, we know we can start with just a few properties: id, name, and category. In the schema.graphql file, add the new Amenity type shown below:

type Amenity {
id: ID!
"The amenity category the amenity belongs to"
category: String!
"The amenity's name"
name: String!
}

And from the schema's perspective, our work is done!

After saving our changes, the codegen process should have run automatically. We can check types.ts to make sure that our new Amenity type has been added!

types.ts
export type Amenity = {
__typename?: "Amenity";
/** The amenity category the amenity belongs to */
category: Scalars["String"]["output"];
id: Scalars["ID"]["output"];
/** The amenity's name */
name: Scalars["String"]["output"];
};
Task!

Testing the Amenity type

Jump back into the Explorer. We'll try running a that calls for a listing's amenities details.

query GetListing($listingId: ID!) {
listing(id: $listingId) {
title
numOfBeds
amenities {
name
category
}
}
}

And make sure that in the Variables panel, our $listingId is still set.

{ "listingId": "listing-1" }

And when we run the ... amenity data for our listing!

An alternate path

Now what about the featuredListings path? It's another entry point to our schema that returns a list of Listing types, for which we could then request the amenities . Let's try it out.

GraphQL operation
query GetFeaturedListings {
featuredListings {
id
title
description
amenities {
id
name
category
}
}
}

Uh-oh!

http://localhost:4000

A screenshot of the Explorer, showing an error when we query for amenities on featured listings

An error appears in the Response panel rather than the data we want. But what's the problem?

Error message
"Cannot return null for non-nullable field Amenity.name."

We were able to return amenities data for a single listing, but something's going wrong when we try to include it for each of our featured listings.

Key takeaways

  • An 's can return types or other object types.
  • When a on an returns another , we can write complex queries that traverse from one object to another—no follow-up queries necessary!

Up next

Let's investigate the source of that error and fix it.

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.