Docs
Launch GraphOS Studio
You're viewing documentation for a previous version of this software. Switch to the latest stable version.

10. Authenticate your queries


In this section, you will book a flight 🚀! Booking a flight requires being authenticated to the server so the correct person is sent to space! To do that, and since Apollo Android is using

to handle HTTP requests, you will use OkHttp
Interceptors
to add headers to your requests.

Add the interceptor

In Apollo.kt, add the AuthorizationInterceptor class:

app/src/main/kotlin/com/example/rocketreserver/Apollo.kt
private class AuthorizationInterceptor(val context: Context): Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.addHeader("Authorization", User.getToken(context) ?: "")
.build()
return chain.proceed(request)
}
}

This interceptor appends an "Authorization: $token" HTTP header to every request.

Use the interceptor

Create a custom OkHttpClient that will use this interceptor and pass it to the ApolloClient:

app/src/main/kotlin/com/example/rocketreserver/Apollo.kt
instance = ApolloClient.builder()
.serverUrl("https://apollo-fullstack-tutorial.herokuapp.com/")
.okHttpClient(OkHttpClient.Builder()
.addInterceptor(AuthorizationInterceptor(context))
.build()
)
.build()

Notice that Apollo.kt now requires a context to create the interceptor and read the token from the EncryptedSharedPreferences. apolloClient cannot be a top level anymore, so transform it to a top-level method that takes a context parameter instead:

app/src/main/kotlin/com/example/rocketreserver/Apollo.kt
fun apolloClient(context: Context): ApolloClient {
return ApolloClient.builder()
.serverUrl("https://apollo-fullstack-tutorial.herokuapp.com/")
.okHttpClient(OkHttpClient.Builder()
.addInterceptor(AuthorizationInterceptor(context))
.build()
)
.build()
}

Replace all usages of apolloClient with apolloClient(context). There is one instance in each :

// LaunchListFragment
apolloClient(requireContext()).query(LaunchListQuery(cursor = Input.fromNullable(cursor))).await()
// LaunchDetailsFragment
apolloClient(requireContext()).query(LaunchDetailsQuery(id = args.launchId)).await()
// LoginFragment
apolloClient(requireContext()).mutate(LoginMutation(email = Input.fromNullable(email))).await()

There is no need to create a new instance of the apolloClient for each request. You can reuse a single instance like so:

private var instance: ApolloClient? = null
fun apolloClient(context: Context): ApolloClient {
if (instance != null) {
return instance!!
}
instance = ApolloClient.builder()
.serverUrl("https://apollo-fullstack-tutorial.herokuapp.com/")
.okHttpClient(
OkHttpClient.Builder()
.addInterceptor(AuthorizationInterceptor(context))
.build()
)
.build()
return instance!!
}

Note: The singleton is handled here manually for sample purposes. In a real-life application, you would certainly use a dependency injection framework such as Dagger or Koin.

Add the BookTrip and CancelTrip mutations

Next to schema.json add a BookTrip.graphql file:

app/src/main/graphql/com/example/rocketreserver/BookTrip.graphql
mutation BookTrip($id:ID!) {
bookTrips(launchIds: [$id]) {
success
message
launches {
id
}
}
}

Notice how the bookTrips takes a list as but the itself only take a single .

Also add the CancelTrip.graphql file. This doesn't use lists:

app/src/main/graphql/com/example/rocketreserver/CancelTrip.graphql
mutation CancelTrip($id:ID!) {
cancelTrip(launchId: $id) {
success
message
launches {
id
}
}
}

Connect the mutations to your UI

Connect the to the Book Now button:

Go back to LaunchDetailsFragment.kt. In the button click listener, after checking for the user token, add the following code:

app/src/main/java/com/example/rocketreserver/LaunchDetailsFragment.kt
binding.bookButton.visibility = View.INVISIBLE
binding.bookProgressBar.visibility = View.VISIBLE
lifecycleScope.launchWhenResumed {
val mutation = if (isBooked) {
CancelTripMutation(id = args.launchId)
} else {
BookTripMutation(id = args.launchId)
}
val response = try {
apolloClient(requireContext()).mutate(mutation).await()
} catch (e: ApolloException) {
configureButton(isBooked)
return@launchWhenResumed
}
if (response.hasErrors()) {
configureButton(isBooked)
return@launchWhenResumed
}
configureButton(!isBooked)
}

This sends the appropriate based on whether the is booked.

Book your trip!

Compile and run your app. You can now book and cancel your trips!

In the next section, you will

and be notified in real time when someone books a flight.

Previous
9. Write your first mutation
Next
11. Write your first subscription
Edit on GitHubEditForumsDiscord

© 2024 Apollo Graph Inc.

Privacy Policy

Company