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

10. Authenticate your operations


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 Kotlin is using OkHttp to handle HTTP requests, you will use an OkHttp Interceptor 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() : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.apply {
TokenRepository.getToken()?.let { token ->
addHeader("Authorization", token)
}
}
.build()
return chain.proceed(request)
}
}

This interceptor appends an "Authorization: $token" HTTP header to requests if the token is not null.

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
val apolloClient = ApolloClient.Builder()
.serverUrl("https://apollo-fullstack-tutorial.herokuapp.com/graphql")
.okHttpClient(
OkHttpClient.Builder()
.addInterceptor(AuthorizationInterceptor())
.build()
)
.build()

Add the BookTrip and CancelTrip mutations

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

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

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

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

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

Connect the mutations to your UI

Go back to LaunchDetails.kt, and replace the TODOs in onBookButtonClick by executing the appropriate mutation based on whether the is booked:

app/src/main/java/com/example/rocketreserver/LaunchDetails.kt
private suspend fun onBookButtonClick(launchId: String, isBooked: Boolean, navigateToLogin: () -> Unit): Boolean {
if (TokenRepository.getToken() == null) {
navigateToLogin()
return false
}
val mutation = if (isBooked) {
CancelTripMutation(id = launchId)
} else {
BookTripMutation(id = launchId)
}
val response = apolloClient.mutation(mutation).execute()
return when {
response.exception != null -> {
Log.w("LaunchDetails", "Failed to book/cancel trip", response.exception)
false
}
response.hasErrors() -> {
Log.w("LaunchDetails", "Failed to book/cancel trip: ${response.errors?.get(0)?.message}")
false
}
else -> true
}
}

Now back to the LaunchDetails function, declare a coroutine scope to be able to call the suspend onBookButtonClick. Also, let's remember isBooked and change the button's text accordingly:

app/src/main/java/com/example/rocketreserver/LaunchDetails.kt
// Book button
val scope = rememberCoroutineScope()
var isBooked by remember { mutableStateOf(data.launch?.isBooked == true) }
Button(
modifier = Modifier
.padding(top = 32.dp)
.fillMaxWidth(),
onClick = {
scope.launch {
val ok = onBookButtonClick(
launchId = data.launch?.id ?: "",
isBooked = isBooked,
navigateToLogin = navigateToLogin
)
if (ok) {
isBooked = !isBooked
}
}
}
) {
Text(text = if (!isBooked) "Book now" else "Cancel booking")
}

Let's also add a loading indicator and prevent the button from being clicked while the mutation is running:

app/src/main/java/com/example/rocketreserver/LaunchDetails.kt
// Book button
var loading by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
var isBooked by remember { mutableStateOf(data.launch?.isBooked == true) }
Button(
modifier = Modifier
.padding(top = 32.dp)
.fillMaxWidth(),
enabled = !loading,
onClick = {
loading = true
scope.launch {
val ok = onBookButtonClick(
launchId = data.launch?.id ?: "",
isBooked = isBooked,
navigateToLogin = navigateToLogin
)
if (ok) {
isBooked = !isBooked
}
loading = false
}
}
) {
if (loading) {
SmallLoading()
} else {
Text(text = if (!isBooked) "Book now" else "Cancel booking")
}
}

Book your trip!

Compile and run your app. You can now book and cancel your trips! The button will change based on whether a trip has been booked or not.

In the next section, you will write your first subscription 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