4. Subscriptions over HTTP callbacks
15m

Overview

Before we can send through our federated , we need to tell our locally-running (part of the rover dev process) exactly how it should handle events.

In this lesson, we will:

  • Learn about the HTTP callback event loop
  • Use the router-config.yaml file to configure the for over HTTP callback

Subscriptions and router-config.yaml

To enable in our federated , we'll turn back to the router-config.yaml file. This is the configuration file where we can provide all kinds of details about how the should run—including how it should handle events, and which protocol to use for which .

Let's open up router/router-config.yaml.

First, we'll add a top-level key called subscription. On the level below this (indented in), we'll define two extra properties: enabled, which we'll set to true, and mode.

router-config.yaml
# ...other router config properties
subscription:
enabled: true
mode: # TODO

Beneath the mode key, we'll specify some additional properties. This is where we can enable one of two methods: WebSockets (denoted as passthrough) and HTTP callbacks (denoted as callback). We'll stick with callback for this course.

Note: To explore all possible configuration options in the router.yaml file, check out the official documentation.

router-config.yaml
subscription:
enabled: true
mode:
callback:

Next, we'll add the remaining properties that nest beneath the callback property, and then walk through them one-by-one.

router-config.yaml
subscription:
enabled: true
mode:
callback:
public_url: http://127.0.0.1:4000/callback
listen: 127.0.0.1:4000
path: /callback
heartbeat_interval: 15s
subgraphs:
- messages

public_url

The public_url property represents the 's public URL that must be able to send new data to. This is the "callback URL" that the router sends to the subgraph. Our locally running router runs on http://127.0.0.1:4000, and we've appended /callback as the specific endpoint the should use when "calling back" to the (this is the default value the router will use unless we provide a different value).

listen

The listen property specifies the IP address and port the will listen on for callbacks. We haven't changed it from the default value here; but note that for security reasons, it's best to expose a separate port that's available only through your internal network.

path

The path property states the specific path of our 's callback endpoint. It should match the value appended to the public_url. If you don't specify a path here, it takes the value of /callback by default.

heartbeat_interval

The hearbeat_interval property specifies an interval at which the should "check in" with the . By default, the router asks the subgraph to send a "check" message every five seconds.

Note: The heartbeat_interval property is optional. You might not want your constantly checking in—particularly if your architecture follows a pay-by-function-call model! You can disable these check-ins by passing disabled in place of the number of seconds.

subgraphs

Lastly, under subgraphs, we specify the names of the that use the HTTP callback protocol to provide data. We have just one: messages.

The subscription initialization

Let's see what these new configuration properties mean for our . We'll walk through the setup process using an example from earlier.

subscription SubscribeToMessagesInConversation(
$listenForMessageInConversationId: ID!
) {
listenForMessageInConversation(id: $listenForMessageInConversationId) {
text
sentTime
}
}

When the receives this , it creates the and determines that the entire operation is the responsibility of the messages . So, it sends it onward—including extra information about how to call back. Here's what this looks like.

{
"query": "subscription SubscribeToMessagesInConversation(){...}", // remainder of subscription operation
"extensions": {
"subscription": {
"callbackUrl": "http://127:0.0.1:4000/callback/randomly-assigned-subscription-hash",
"subscriptionId": "randomly-assigned-subscription-hash",
"verifier": "XYZ", // a unique property
"heartbeatIntervalMs": 15000
}
}
}

That's a lot of helpful data! Let's take a closer look at what we're working with here.

In addition to the itself, the object contains the callbackUrl and the heartbeatIntervalMs values that we provided in the router-config.yaml (with the exception of seconds being converted to milliseconds). Additionally, the will assign a subscriptionId for the very specific it sends to the .

Finally, we have a property called verifier. The verifier is used to verify the 's identity with the every time it sends a new message—it's how the knows who it's talking to and whether the source is legitimate.

A diagram of the router and subgraph, with the router providing the verifier that should be used in future communication

Upon receiving this big object from the , the includes the verifier in its first response back to the to make contact. The router responds with confirmation, and the initializes the by sending back an empty object. With that, setup is complete! And we're ready for updates.

The subscription loop

With our setup complete, the loop begins. Here's what happens under the hood:

  1. Every five seconds, the takes on its emitter role and sends the a "check" message. Kind of like saying "Are you still there?" every once in awhile—if the responds, the loop continues.
  2. When the detects a event (new data!) it sends the a "next" message containing the data.
  3. If something goes wrong or the should be terminated, the sends a "complete" message and the ends the .

You don't need to do anything special to handle these "check", "next" and "complete" messages. This is handled out-of-the-box by our implementations. These additional details can serve as a guide for anyone working on an implementation of the HTTP Callback Protocol.

If we do nothing else in our , the and will continue checking in every five seconds. But as soon as we trigger some change to our pertinent data, the subgraph has something substantial to share. The router receives this new data, packages it up with anything else it needed to fetch across the graph, and returns it all to the client. And the loop goes on!

Re-running rover dev

We've provided a bunch of configuration for our locally-running to use; now let's just restart the rover dev process and make sure that we're actually using it!

APOLLO_KEY="..." \
APOLLO_GRAPH_REF="..." \
rover dev \
--supergraph-config supergraph.yaml \
--router-config router-config.yaml

Run this command, passing in your own values for APOLLO_GRAPH_REF and APOLLO_KEY. And with that, we should have success!

==> your supergraph is running! head to http://localhost:4000 to query your supergraph

Practice

HTTP Callback Protocol
When implementing the HTTP Callback Protocol, the router and subgraph communicate over 
 
. The configuration property called 
 
 lets us set how frequently the subgraph should check in with the router. Including this property in the configuration file is 
 
. Whenever new data is available, the subgraph sends it to the router along with a special property called the 
 
, which confirms its identity with the router. This process can optionally include a separate component to manage the ongoing check-ins and data transmission called the 
 
.

Drag items from this box to the blanks above

  • a long-lived, persistent connection

  • heartbeat_interval

  • checkin_interval

  • required

  • BFF

  • a callback URL

  • optional

  • authorization

  • emitter

  • verifier

  • communicator

Key takeaways

  • The HTTP callback protocol allows the and to stay in contact, checking in periodically and sharing updates as they happen.
  • This protocol can optionally include a third mechanism, the emitter, which can take on the responsibility of checking in with the as well as conveying new data.
  • The provides the with a callback URL where the subgraph (or emitter) can send its messages when checking in and sharing updates.
  • The also provides a verifier, a unique value that the should include with every communication to verify its identity.

Up next

Our process is ready to handle our —now let's finish up our logic and start sending messages!

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.