6. Sending APQ to subgraphs
10m

Overview

The can also play the role of client—when it sends individual, smaller queries to each . Accordingly, it can also use to shorten its requests to subgraphs.

In this lesson, we will:

  • Configure the to send to s
  • Test out in a request to the listings

Sending APQ to subgraphs

We can use the router-config.yaml file to customize how the handles with its .

We'll need a top-level apq key, with another key nested below called subgraph. (If you added a router key from the previous step, the subgraph key can sit on the same level.)

router-config.yaml
apq:
subgraph:
router: # optional configuration for client APQ behavior

Under the subgraph key, we can specify settings for all , or override the rules for a specific subgraph. Let's try this out, disabling globally while enabling it for a single subgraph: listings.

router-config.yaml
apq:
subgraph:
all:
enabled: false
subgraphs:
listings:
enabled: true
router: # router configuration

Then, restart the to make use of these new settings; make sure to include the --log flag, and pass it a value of trace.

APOLLO_KEY=<APOLLO_KEY> \
APOLLO_GRAPH_REF=<APOLLO_GRAPH_REF> \
./router --config router-config.yaml \
--log trace

Now, when communicating with the listings , the can send it the identifier of the smaller string it would normally send. Provided that the listings is configured to understand this hash and use it correctly, that's all that's needed! And in our case, because the listings is powered by , it can handle the without any trouble at all.

Let's return to the we inspected in the last lesson. It consists of two components that can run in sequence: one query sent to the listings first, followed by a to reviews.

QueryPlan {
Sequence {
Fetch(service: "listings") {
{
listing(id: $listingId) {
__typename
id
title
description
numOfBeds
}
}
},
Flatten(path: "listing") {
Fetch(service: "reviews") {
{
... on Listing {
__typename
id
}
} =>
{
... on Listing {
overallRating
reviews {
id
text
}
}
}
},
},
},
}

Let's zoom in on the request to listings. For the given $listingId, the listings service needs to provide a number of .

{
listing(id: $listingId) {
__typename
id
title
description
numOfBeds
}
}

Return to Explorer, and let's rerun this to see what happens under the hood of the .

query GetListingAndReviews($listingId: ID!) {
listing(id: $listingId) {
title
description
numOfBeds
overallRating
reviews {
id
text
}
}
}

And in the Variables panel.

{
"listingId": "listing-1"
}

After running the , return to the 's terminal. We could scroll through its output to find the exact line we're looking for, but let's expedite things by searching directly for the following line, which references the SHA-256 hash generated for the query being sent to listings.

\"sha256Hash\":\"8c6389470a25e2b57141aeb1aee624f77b8310e90563a17a11ebced119756fe8\\"

This brings us to a specific bit of output that starts with "our JSON body:". Here we can find both the string, along with the SHA-256 hash that was generated for it.

our JSON body: "{
\"query\":\"query GetListingAndReviews__listings__0($listingId:ID!){listing(id:$listingId){__typename id title description numOfBeds}}\",
\"operationName\":\"GetListingAndReviews__listings__0\",
\"variables\":{\"listingId\":\"listing-1\"},
\"extensions\":{
\"persistedQuery\":{
\"version\":1,
\"sha256Hash\":\"8c6389470a25e2b57141aeb1aee624f77b8310e90563a17a11ebced119756fe8\"
}
}
}"

The first time the sends this request to the listings , it includes the full string along with the hash. This enables us to send just the hash on subsequent requests.

We'll send the listings service another separate request to demonstrate this. Open a new terminal, and build the following curl command to the listings service at https://rt-airlock-subgraphs-listings.herokuapp.com/. This time, we won't send the string—just the hash. (But note that we do still need to provide a value for our , listingId!)

curl --get https://rt-airlock-subgraphs-listings.herokuapp.com/ \
--header 'content-type: application/json' \
--data-urlencode 'variables={"listingId":"listing-1"}' \
--data-urlencode 'extensions={"persistedQuery":{"version":1,"sha256Hash":"8c6389470a25e2b57141aeb1aee624f77b8310e90563a17a11ebced119756fe8"}}'

Note: To provide the object for our , we use an additional --data-urlencode flag that sets the variables property with the appropriate value.

Now that the listings service has already received the string this hash refers to, it knows exactly what to do the second time we send it. The hash, along with the appropriate , is enough to get data back!

The response from listings
{
"data": {
"listing": {
"__typename": "Listing",
"id": "listing-1",
"title": "Cave campsite in snowy MoundiiX",
"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.",
"numOfBeds": 2
}
}
}

And because we used ($listingId) in our original , we can change the value we provide on the fly; the same hash will continue to work.

Try it out with a different variable!
curl --get https://rt-airlock-subgraphs-listings.herokuapp.com/ \
--header 'content-type: application/json' \
--data-urlencode 'variables={"listingId":"listing-3"}' \
--data-urlencode 'extensions={"persistedQuery":{"version":1,"sha256Hash":"8c6389470a25e2b57141aeb1aee624f77b8310e90563a17a11ebced119756fe8"}}'

You might have also noticed logs detailing the component of the that was sent to the reviews : this request did NOT include a hash of the . Per our configuration, we enabled exclusively for the listings !

Practice

Which of the following statements describes router-to-subgraph APQ?

Key takeaways

  • The can also use in the queries it sends to . This feature can be enabled globally or on an individual subgraph basis. Subgraphs built with support APQ out of the box.

Up next

With , we can reduce the amount of data we send over the wire; but caching them still relies upon the 's (or 's) in-memory cache. In the next lesson, we'll take our caching to the next level with a distributed cache multiple instances can share.

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.