Overview
We have our featured listings, and one of them is really catching our eye, so how do we query just one specific listing and all its details?
In this lesson, we will:
- Learn how to access GraphQL arguments in a connector
Listing details
Here's what the mockup looks like for a listing's details:
Mapping this back to our REST API, we'll need to retrieve this data from the GET /listings/:id
endpoint, passing a listing ID into the URL. We can examine the response from that endpoint here: https://airlock-listings.demo-api.apollo.dev/listings/listing-1
{"costPerNight": 120,"title": "Cave campsite in snowy MoundiiX","locationType": "CAMPSITE","description": "Enjoy this amazing cave campsite in snow MoundiiX, where you'll be one with the nature and wildlife in this wintery planet. All space survival amenities are available. We have complementary dehydrated wine upon your arrival. Check in between 34:00 and 72:00. The nearest village is 3AU away, so please plan accordingly. Recommended for extreme outdoor adventurers.","id": "listing-1","numOfBeds": 2,"closedForBookings": false,"photoThumbnail": "https://res.cloudinary.com/apollographql/image/upload/v1644350721/odyssey/federation-course2/illustrations/listings-01.png","hostId": "user-1","isFeatured": true,"latitude": 1023.4,"longitude": -203.4,"amenities": [{"id": "am-2","category": "Accommodation Details","name": "Towel"},{"id": "am-10","category": "Space Survival","name": "Oxygen"}// more amenities]}
The listing
connector
In the schema, let's find the
Query
type and add a new field calledlisting
, which takes in anid
argument of type non-nullableID
and returns a nullableListing
type.listings.graphqltype Query {# ...other fields"A specific listing"listing(id: ID!): Listing}Note: If you're not familiar with how to use GraphQL arguments, you can learn about them at graphql.com/learn/arguments.
Saving our changes,
rover dev
will now give us that expected (and helpful!) error. We know how to fix that!error[E029]: Encountered 1 build error while trying to build a supergraph.Caused by:QUERY_FIELD_MISSING_CONNECT: [listing] The field `Query.listing` has no `@connect` directive.Let's add the
@connect
directive to the field, auto-completing the parameters by hitting Enter.listings.graphqllisting(id: ID!): Listing@connect(source: ""http: { GET: "" }selection: """""")We'll use the same
source
as before:listings
.listings.graphqlsource: "listings"And we're doing an HTTP
GET
call to/listings/:id
.listings.graphqlhttp: { GET: "/listings/ID???" }
But what do we put for the id
? We can't hard-code an id
like we did in the browser. We want to make it dynamic, pulling from the id
the client would provide. So how do we get access to the value of that listing id
argument here in the @connect
directive?
listing(id: ID!): Listing # ⬅️ Here's the id value we need!@connect(source: ""http: { GET: "/listings/ID???" } # ⬅️ Here's where we need it to end up!selection: """""")
Accessing GraphQL arguments in connectors
args
to the rescue! args
gives us access to all of the field's arguments. But we'll need to prefix it with the dollar sign symbol ($
), which indicates a variable in GraphQL.
Taking this schema as an example:
type Query {spaceCats(name: String!, team: String!, mission: ID!): SpaceCat}
We can access the field's arguments with $args.name
, $args.team
and $args.mission
.
And to interpolate these values into the path in our connector, we'll need to wrap them in curly braces ({ }
).
Let's try it out!
Using $args
We have the start of the endpoint with the path
/listings/
.listings.graphqlhttp: { GET: "/listings/" }Then, because we want to access the field's
id
argument, we'll use$args.id
, making sure to wrap it in curly braces ({}
) to include it in the path.listings.graphqlhttp: { GET: "/listings/{$args.id}" }Watch out for the syntax here: the dollar sign (
$
) is inside the curly braces.Great! All that's left to do is fill in our
selection
. The JSON response for this endpoint is actually very similar to thefeaturedListings
connector, a mostly one-to-one mapping, with the exception of theclosedForBooking
field. The mockup also shows a list of amenities that belong to the listing, but we'll tackle that in the next lesson. For now, let's keep going.listings.graphqlselection: """idtitlenumOfBedscostPerNightclosedForBooking: closedForBookings"""
Checking our work
You know the drill! Save your changes and open up Sandbox.
Here we'll build a new operation, so open up a new tab, and we'll retrieve a specific listing and all of its fields.
We can hit the plus button to add all the available fields in one go.
We'll give this operation a new name: GetListingDetails
.
query GetListingDetails($listingId: ID!) {listing(id: $listingId) {idtitlenumOfBedscostPerNightclosedForBooking}}
Under the Variables section, we'll add the listingId
value.
{"listingId": "listing-1"}
Hit Run and... we can see the details of one specific listing now! Awesome!
{"data": {"listing": {"id": "listing-1","title": "Cave campsite in snowy MoundiiX","numOfBeds": 2,"costPerNight": 120,"closedForBooking": false}}}
Practice
Answer the following questions using the schema below:
type Query {allListings(limit: Int = 10, offset: Int): [Listing!]!}
limit
argument in the allListings
field's connector?Use the REST API JSON response below to complete the code challenge.
{"id": "px-m012","officialName": "Mraza","mass": 6.42}
Replace the ???
instances in the http.GET
path with the correct values from the field arguments. Refer to the resulting JSON object above to define the selection.
Key takeaways
- To access a field's argument values from within its connector, we can use
$args
. This is an object that contains the values of all of the arguments that are passed into a field when a query is run. - To interpolate the value of an argument as a URL parameter in the path, we can use curly braces. For example:
http: { GET: "/listings/{$args.id}"}
Up next
We're on a roll! But we didn't quite finish up our listing details, we're still missing a listing's amenities. Let's tackle that next.
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.