11. Write your first subscription


In this section, you will use subscriptions to get notified whenever someone books a flight 🚀! Subscriptions allow to be notified in real time whenever an event happens on your server. The fullstack backend supports subscriptions based on WebSockets.

Write your subscription

Open GraphQL Playground and open the docs tab on the right. In addition to queries and mutations, you will see a third type of operations, subscriptions. Click the tripsBooked subscription:

The definition of tripsBooked in the schema

This subscription doesn't take any argument and returns a single scalar named tripsBooked. Since the you 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.

Type the following subscription in the left panel:

GraphQL
1subscription {
2  tripsBooked
3}

Click the Play button, your subscription will start listening to events.

Test your subscription with GraphQL Playground

Leave this tab open and open GraphQL Playground in a new one. In this new tab, book a trip like on step 9:

GraphQL
1mutation {
2  bookTrips(launchIds: ["83"]){
3    message
4  }
5}

Do not forget to include the authentication header:

JSON
1{
2  "Authorization": "The header you got from the login mutation"
3}

Click the Play button. If everything went well, you just booked a trip. Go back to your subscription tab and you should see an event in the right panel:

Your first subscription

Continue booking and/or canceling trips, you will see events coming in the subscription tab 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 the project

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

GraphQL
app/src/main/graphql/com/example/rocketreserver/TripsBooked.graphql
1subscription TripsBooked {
2  tripsBooked
3}

Configure your ApolloClient to use subscriptions

In Apollo.kt, add a SubscriptionTransport.Factory to your ApolloClient. Here it uses a WebSocketSubscriptionTransport.Factory and OkHttp:

Kotlin
Apollo.kt
1    val okHttpClient = OkHttpClient.Builder()
2        .addInterceptor(AuthorizationInterceptor(context))
3        .build()
4
5    instance = ApolloClient.builder()
6        .serverUrl("https://apollo-fullstack-tutorial.herokuapp.com/graphql")
7        .subscriptionTransportFactory(WebSocketSubscriptionTransport.Factory("wss://apollo-fullstack-tutorial.herokuapp.com/graphql", okHttpClient))
8        .okHttpClient(okHttpClient)
9        .build()

wss:// is the protocol for WebSocket.

Display a SnackBar when a trip is booked/cancelled

In MainActivity, register your subscription and start listening to events using coroutine Flows. Use a Material SnackBar to display a small message coming from the bottom of the screen:

Kotlin
MainActivity.kt
1    override fun onCreate(savedInstanceState: Bundle?) {
2        super.onCreate(savedInstanceState)
3
4        setContentView(R.layout.activity_main)
5
6        lifecycleScope.launch {
7            apolloClient(this@MainActivity).subscribe(TripsBookedSubscription()).toFlow()
8                .collect {
9                    val text = when (val trips = it.data?.tripsBooked) {
10                        null -> getString(R.string.subscriptionError)
11                        -1 -> getString(R.string.tripCancelled)
12                        else -> getString(R.string.tripBooked, trips)
13                    }
14                    Snackbar.make(
15                        findViewById(R.id.main_frame_layout),
16                        text,
17                        Snackbar.LENGTH_LONG
18                    ).show()
19                }
20        }
21    }

Handle errors

Like for queries and mutations, the subscription will throw an error if the connection is lost or any other protocol error happens. To handle these situations, you can use Flow.retry:

mainactivity.kt
1    apolloClient(this@MainActivity).subscribe(TripsBookedSubscription()).toFlow()
2        .retryWhen { _, attempt ->
3            delay(attempt * 1000)
4            true
5        }
6        .collect {
7            // ...

Test your code

Build and run your app and go back to your second GraphQL Playground tab. Book a new trip while your app is open, you should see a SnackBar 🚀:

A trip has been booked

This concludes the tutorial.

More resources

Use the rest of this documentation for more advanced topics like Caching or Gradle configuration.

Feel free to ask questions by either opening an issue on our GitHub repo or stopping by our Spectrum Chat for help.

And if you want dig more and see GraphQL in real-life apps, you can take a look at these open source projects using Apollo Android:

Feedback

Edit on GitHub

Forums