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 SDL syntax, fields on GraphQL types don't have to return a basic scalar type—they can also return other object types!
For instance, we can give our Listing
type an amenities
field—but what does this field actually return?
type Listing {id: ID!title: String!description: String!numOfBeds: Int!costPerNight: Float!closedForBookings: Booleanamenities: # 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 entity—in other words, we should make it its own GraphQL type called Amenity
.
This means that our Listing
type should be updated: we need its amenities
field to return a list of Amenity
types!
Update your Listing
type with the amenities
description and field 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.
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}
Let's recompile and jump back into the Explorer. We'll try running a query that calls for a listing's amenities
details.
query GetListing($listingId: ID!) {listing(id: $listingId) {titlenumOfBedsamenities {namecategory}}}
And make sure that in the Variables panel, our $listingId
variable is still set.
{ "listingId": "listing-1" }
And when we run the query... 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
field.
Let's try it out.
query GetFeaturedListings {featuredListings {idtitledescriptionamenities {idnamecategory}}}
Uh-oh!
An error appears in the Response panel rather than the data we want. But what's the problem?
"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 object type's fields can return scalar types or other object types.
- When a field on an object type returns another object type, 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.
Share your questions and comments about this lesson
This course is currently in
You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.