8. Write your first subscription
13m

Overview

Query and Mutation aren't the only types in ā€”when we want real-time updates about server-side events, we'll need the third and final GraphQL type: the Subscription!

In this lesson, we will:

  • Configure ApolloClient to use WebSockets
  • Write a to receive booking notifications
  • Test the in-app

Apollo Kotlin and subscriptions

With subscriptions, we can get notifications about real-time events as they happen. We'll spend this last lesson of the course exploring how we can build a subscription operation to receive a notification when someone books a seat on a launch! šŸš€

supports WebSockets and Multipart HTTP for . For this tutorial we'll use WebSockets.

Note: To learn more about Multipart HTTP, see Multipart HTTP protocol for GraphQL Subscriptions.

Let's create a subscription!

Open up Sandbox, or use the embedded Explorer in the collapsible section below.

Click on the Schema tab at the far left. In addition to queries and mutations, we'll find a third type, Subscription. Click on Subscription to see the tripsBooked :

https://studio.apollographql.com/sandbox/schema

Sandbox opened to the Schema page, with focus on the Subscription type. Its tripsBooked field is highlighted

This doesn't take any and returns a single named tripsBooked. Since we can book multiple trips at once, tripsBooked is an Int. It will contain the number of trips booked at once or -1 if a trip has been cancelled.

Click the play button to the far right of tripsBooked to open the in Explorer. Open a new tab, then check the tripsBooked button to have the added:

https://studio.apollographql.com/sandbox/explorer

Sandbox opened to the Explorer page, where a new subscription operation has been added

Again, we'll rename the so it's easier to find:

subscription TripsBooked {
tripsBooked
}

Click the Submit button, and the will start listening to events. We can tell it's up and running because a panel will pop up at the lower right where subscription data will come in:

https://studio.apollographql.com/sandbox/explorer

The Explorer UI updated to show that a subscription has been submitted and Explorer is now listening for events

Test your subscription

Open a new tab in Explorer. In this new tab, add code to book a trip like in the previous lesson, but with a hard-coded ID:

mutation BookTrip {
bookTrips(launchIds: ["93"]) {
message
}
}

Don't forget to include the authentication header! Make sure the Headers section in the Operation panel is populated with your token.

Authorization token
bWVAZXhhbXBsZS5jb20=

Click the Submit button. If everything went well, we've just booked a trip! At the top of the right panel, we'll see the success JSON for our BookTrip , and below it, updated JSON for the TripsBooked :

https://studio.apollographql.com/sandbox/explorer

The Explorer UI updated with a successfully booked trip event

Continue booking and/or canceling trips! We'll see events arriving in the panel in real time. After some time, the server might close the connection and you'll have to restart your subscription to keep receiving events.

Add the subscription to your project

Now that your is working, add it to your project. Create a file named TripsBooked.graphql next to schema.graphqls and your other files and paste the contents of the . The process is similar to what you did for queries and :

app/src/main/graphql/TripsBooked.graphql
subscription TripsBooked {
tripsBooked
}

Don't forget to run a build!

Configure ApolloClient to use subscriptions

This lesson uses the subscriptions-transport-ws protocol for . For more options like the newer graphql-ws or Appsync, see GraphQL over WebSocket protocols.

In Apollo.kt, configure a webSocketServerUrl for your ApolloClient:

Apollo.kt
val apolloClient = ApolloClient.Builder()
.serverUrl("https://apollo-fullstack-tutorial.herokuapp.com/graphql")
.webSocketServerUrl("wss://apollo-fullstack-tutorial.herokuapp.com/graphql")
.okHttpClient(...)
.build()

Now, we're ready to actually use our !

Use the subscription

In MainActivity, register your and keep a reference to the returned coroutine Flow.

Use collectAsState to get the latest value of the Flow as a state. When the Flow emits a value, it will be stored in tripBookedResponse and trigger a re of the UI thanks to the LaunchedEffect that depends on it.

MainActivity.kt
RocketReserverTheme {
val tripBookedFlow = remember { apolloClient.subscription(TripsBookedSubscription()).toFlow() }
val tripBookedResponse: ApolloResponse<TripsBookedSubscription.Data>? by tripBookedFlow.collectAsState(initial = null)
LaunchedEffect(tripBookedResponse) {
if (tripBookedResponse == null) return@LaunchedEffect
val message = when (tripBookedResponse!!.data?.tripsBooked) {
null -> "Subscription error"
-1 -> "Trip cancelled"
else -> "Trip booked! šŸš€"
}
// TODO use the message
}

Now let's display the message in a Material SnackBar.

To do this, you'll need to create a SnackbarHostState and call showSnackbar on it. Don't forget to also pass it to the Scaffold below:

MainActivity.kt
val snackbarHostState = remember { SnackbarHostState() }
val tripBookedFlow = (...)
(...)
val message = (...)
snackbarHostState.showSnackbar(
message = message,
duration = SnackbarDuration.Short
)
}
Scaffold(
topBar = { TopAppBar({ Text(stringResource(R.string.app_name)) }) },
snackbarHost = { SnackbarHost(snackbarHostState) },
) { paddingValues ->

Handle errors

Like for queries and , the will throw an error if the connection is lost or any other protocol error happens. To handle these situations, you can configure the client to retry the subscription with the webSocketReopenWhen function. Return true to retry, false to stop. To avoid retrying too often, you can use the attempt parameter to delay the retry:

Apollo.kt
val apolloClient = ApolloClient.Builder()
(...)
.webSocketReopenWhen { throwable, attempt ->
Log.d("Apollo", "WebSocket got disconnected, reopening after a delay", throwable)
delay(attempt * 1000)
true
}

Test your subscription in-app

Build and run the application: now whenever a trip is booked or cancelled (from either in the app detail view or from ) we should see a small notification pop up at the bottom of the screen:

A subscription notification appearing in the UI after a trip is booked or cancelled

Practice

What types of features are GraphQL subscriptions useful for?
What protocols are supported in Apollo Kotlin for subscriptions?

Journey's end

Congratulations on completing the two-part and Android series! You've successfully learned the basics of the Apollo Kotlin SDK to connect your Android app to a . You have:

  • Downloaded a schema
  • Added code generation into your workflow
  • Written and executed queries and in and in your app
  • Learned how to handle errors
  • Used basic authentication
  • Implemented basic pagination
  • Worked with WebSockets to receive real-time updates

So, what's next? Keep your progress going! Check out these resources:

Feel free to ask questions by joining the Apollo GraphQL Forum.

Thank you for choosing !

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.