How We Migrate Android Kitalulus Apollo Client 2.3 to 3.5

Raka Nugroho
Kitalulus Engineering
3 min readSep 19, 2022

At Kitalulus, we mostly use GraphQL as a communication bridge between the client (mobile & web application) and the server. Recently, KitaLulus mobile team worked on migrating our Apollo client from 2.3 to 3.5, and it took a few days to research, debug, monitor, and make sure everything is okay.

Why do we migrate?

Apollo Kotlin 3.0 rewrites most of Apollo Android’s (Version 2. x) internals in Kotlin. Among other improvements, it features:

  • Kotlin-first, coroutine-based APIs
  • A unified runtime for both JVM and multiplatform
  • Declarative cache, @nonnull client directives, performance improvements
  • Proper Caching, at KitaLulus we try to use several caching methodologies like HTTP cache, Automatic Persisted Queries, and Normalized Cache

Migration….

  1. Execution

We can directly consume the queries as a Coroutine since the newest version is Kotlin-first and it exposes suspend functions by default.

Before

suspend fun regist() {   ApolloClient.mutate(
ProfileCreateInput.builder()
.name("Test Name")
.email("test@email.com")
).toDeferred().await()
}

After

fun regist() = 
ApolloClient.mutation(
ProfileCreateInput(name = "Test Name", email = "test@email.com")
)

2. Meta Data

One of the most noticeable advantages is Kotlin-first, we can directly access metadata from response or define variables more easily

mutation createSomeProfile(
$profileCreateInput : ProfileCreateInput!
){
createProfile(payload: $profileCreateInput){
data
error
isSuccess
warning
}
}

Before migration, when we access/create the metadata, we use the factory builder.

ProfileCreateInput.builder()
.name("Test Name")
.email("test@email.com")

After migration, we use Data Class directly 🥳

ProfileCreateInput(name = "Test Name", email = "test@email.com")

3. File Upload

There is a significant change if you have upload file features on your GraphQL, you can read details here

Major Issues

We use sentry to monitor KitaLulus Application performance including network performance. When we tried to upgrade the Apollo client, we must upgrade the sentry Apollo client. But we got some problems with this, when we do mutation and the variables have a new line, it will trigger as ApolloHttpException .

ApolloClient.Builder()
.....
.sentryTracing()

so we must handle Sentry headers to trim or remove the new line, or just remove the headers from your HTTP request like this

class SentryApolloHeaderInterceptor: ApolloInterceptor {
override fun <D : Operation.Data> intercept(
request: ApolloRequest<D>,
chain: ApolloInterceptorChain
): Flow<ApolloResponse<D>> {
val builder = request.newBuilder()
val modifyHeaders = request.httpHeaders?.filter { item ->
item.name != SentryApollo3HttpInterceptor.SENTRY_APOLLO_3_VARIABLES
}
builder.httpHeaders(modifyHeaders)
return chain.proceed(builder.build())
}
}

Wrap up & References

We are trying to build a better culture every day, and maybe you are the one who is ready to contribute https://bit.ly/joinKLTeam

--

--