8. Query plans
2m

Overview

Let's dive even deeper, and check out how an actually gets resolved when connectors are involved.

In this lesson, we will:

  • Examine an 's
  • Optimize a connector's selection mapping to save an extra network call

A listing's amenities

Let's take a closer look at that GetListingAmenities from the previous lesson.

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

We have two connectors doing the work to resolve data for this . The first connector we added to Query.listing and the second to Listing.amenities.

The takes care of coordinating these calls using its query plan, the set of instructions the follows to fetch and assemble data.

Examining the query plan

  1. In Explorer, let's run the again. Don't forget to define a listingId in the Variables section:

    query GetListingAmenities($listingId: ID!) {
    listing(id: $listingId) {
    id
    title
    amenities {
    id
    name
    category
    }
    }
    }
    {
    "listingId": "listing-9"
    }
  2. Open up the Query Plan panel by clicking on the arrow beside Response.

    studio.apollographql.com/sandbox

    Query plan

  3. We can see two fetch calls: one to GET /listings/{$args.id} and then a follow-up one to GET /listings/{$this.id!}/amenities.

    studio.apollographql.com/sandbox

    Query plan

Optimizing network calls

This is perfectly fine, the extra call to fetch follow-up amenities doesn't look like it's adding much to the response time. But what if we were able to remove the need for an extra call?

  1. Open up the Connectors Debugger panel.

  2. Select the first request to /listings/listing-9.

    studio.apollographql.com/sandbox

    Query plan

  3. Navigate to the Response body. We can see the JSON object we get back does contain amenities information!

    studio.apollographql.com/sandbox

    Response body

    Response body
    {
    "id": "listing-9",
    "title": "The Nostromo in LV-426",
    "description": "Ever wondered what it must be like to be aboard The Nostromo, minus the Xenomorph? Now you can find out!",
    "costPerNight": 474,
    "hostId": "user-6",
    "locationType": "HOUSE",
    "numOfBeds": 4,
    "photoThumbnail": "https://res.cloudinary.com/apollographql/image/upload/v1644353889/odyssey/federation-course2/illustrations/listings-09.png",
    "isFeatured": true,
    "latitude": 123.989,
    "longitude": 534.98,
    "closedForBookings": false,
    "amenities": [
    {
    "id": "am-1",
    "category": "Accommodation Details",
    "name": "Interdimensional wifi"
    },
    {
    "id": "am-2",
    "category": "Accommodation Details",
    "name": "Towel"
    }
    // More amenities data...
    ]
    }

    Since we already have the data we need from the first request, let's make use of it!

  4. Open up the listings.graphql file and find the connector for Query.listing.

    listings.graphql
    listing(id: ID!): Listing
    @connect(
    source: "v1"
    http: { GET: "listings/{$args.id}" }
    selection: """
    id
    title
    numOfBeds
    costPerNight
    closed: closedForBookings
    """
    )
  5. We'll add to our selection mapping! Following the format of our JSON property, we can add amenities to our selection.

    listings.graphql
    selection: """
    id
    title
    numOfBeds
    costPerNight
    closed: closedForBookings
    amenities
    """
  6. If we save our changes right now, we'll get a helpful message from rover dev! Makes sense: Amenity is an , so we need to include at least one of its in the data we return.

    rover dev error message
    error[E029]: Encountered 1 build error while trying to build a supergraph.
    Caused by:
    GROUP_SELECTION_REQUIRED_FOR_OBJECT: `Listing.amenities` is an object, so
    ``@connect(selection:)` on `Query.listing`` must select a group `amenities{}`.
  7. Let's keep adding to the selection. Following the error message, we'll add curly braces. Inside, we can pick the properties we want from each item in our amenities array. That includes: id, category and name.

    listings.graphql
    amenities {
    id
    category
    name
    }
  8. Let's save our changes and rover dev should compose successfully!

Back to the query plan

With those changes, we should have saved ourselves an extra network call. Let's check our work.

  1. Jump back to Explorer and look at the again for GetListingAmenities.

    query GetListingAmenities($listingId: ID!) {
    listing(id: $listingId) {
    id
    title
    amenities {
    id
    name
    category
    }
    }
    }
    {
    "listingId": "listing-9"
    }
  2. Run the and examine the Query Plan.

    studio.apollographql.com/sandbox

    Optimized query plan

    Only one fetch call!

  3. Open up the Connectors Debugger and verify that we only see one request: to the listings/:id endpoint.

    studio.apollographql.com/sandbox

    Optimized requests

We're down to just one call to our REST API! 🎉

Practice

What are some of the tools Sandbox provides to help us examine our REST API requests?

Key takeaways

  • The Query plan option in Explorer lets us inspect how the plans to resolve a particular using connectors, along with the network calls involved.
  • With the Connectors Debugger, we can identify opportunities to reduce network calls and streamline our requests!

Up next

We've tackled queries and retrieving read-only data—now it's time to switch our attention over to manipulating data with !

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.