10. 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.graphqls 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!

Testing the Amenity type

Now when we restart our server, DGS will pick up the changes to the schema and regenerate our Java classes. Our generated folder will have a new Amenity class, and the Listing class will be updated with an amenities property that returns—surprise!—Amenity instances. We'll also see getters and setters to help manage this property.

generated/types/Amenity snippet
package com.example.listings.generated.types;
import java.lang.Object;
import java.lang.Override;
import java.lang.String;
public class Amenity {
private String id;
/**
* The amenity category the amenity belongs to
*/
private String category;
/**
* The amenity's name
*/
private String name;
// ... constructors, getters & setters
}
Task!

Let's recompile and 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, which then has access to its amenities .

Let's try it out.

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

Uh-oh!

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

Error message
"The field at path '/listing/amenities' was declared as a non null type,
but the code involved in retrieving data has wrongly returned a null value."

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

This course is currently in

beta
. 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.