如何使用GraphQL Client: Apollo Android

如何使用GraphQL Client: Apollo Android

一個Android app, 如何使用GraphQL.
本文以最流行的Apollo Android為例來說明.

添加依賴

首先, 添加依賴:
//www.apollographql.com/docs/android/essentials/get-started-kotlin/

注意在android block里這兩個東東都要加上:

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

下載Schema

然後, 下載schema.
可以跑一個introspection query來獲取.

Apollo的Gradle插件貼心地提供了這個功能, 用downloadApolloSchema這個task就可以.

只需要提供server的endpoint和存儲schema.json文件的位置:

./gradlew downloadApolloSchema \
  --endpoint="//your.domain/graphql/endpoint" \
  --schema="src/main/graphql/com/example/schema.json"

如果是需要認證的endpoint:

./gradlew downloadApolloSchema \
  --endpoint="//your.domain/graphql/endpoint" \
  --schema="app/src/main/graphql/com/example" \
  --header="Authorization: Bearer $TOKEN"

這裡我曾經有過一個疑問, 我這個TOKEN屬於哪個用戶的要緊嗎? -> 不要緊.
注意: 此時用的Token只是為了獲取schema, 實際請求的時候還是要帶具體當時的token.

添加.graphql文件, build生成程式碼

找Playground測試, 比如GitHub GraphQL API可以用Explorer測試: //developer.github.com/v4/explorer/

然後把這個.graphql文件寫在schema文件旁邊.
比如:
CurrentUser.graphql中:

query CurrentUser {
  viewer {
    login
    avatarUrl
    name
  }
}

Build, 生成程式碼.

生成程式碼在生成文件的路徑.
比如CurrentUser.graphql裡面是一個query, 就生成了CurrentUserQuery文件.

進行請求調用 (協程版本)

採用協程版本的程式碼, 在ViewModel的scope裡面:

viewModelScope.launch {
    val response = try {
        apolloClient.query(CurrentUserQuery()).toDeferred().await()
    } catch (e: ApolloException) {
        // handle protocol errors
        return@launch
    }

    val viewer = response.data?.viewer
    if (viewer == null || response.hasErrors()) {
        // handle application errors
        return@launch
    }
    _user.postValue(viewer)

    println("Launch site: ${viewer.login}")
}

其中toDeferred()方法將結果轉換為Deferred<T>, 是Job的一個子類, await()方法返回協程的結果.

Apollo Client Android的協程支援

添加了這個依賴之後:

implementation("com.apollographql.apollo:apollo-coroutines-support:2.2.3")

會有一個輔助類, 裡面目前是5個擴展方法:

  • Converts an [ApolloCall] to an [Flow]
  • Converts an [ApolloQueryWatcher] to an [Flow].
  • Converts an [ApolloCall] to an [Deferred].
  • Converts an [ApolloSubscriptionCall] to an [Flow].
  • Converts an [ApolloPrefetch] to [Job].

認證請求

關於認證的請求:
//www.apollographql.com/docs/android/tutorial/10-authenticate-your-queries/

同樣也是加interceptor來解決:

return ApolloClient.builder()
    .serverUrl("//api.github.com/graphql")
    .okHttpClient(
        OkHttpClient.Builder()
            .addInterceptor(authInterceptor)
            .build()
    )
    .build()

其中authInterceptor和用Retrofit時候的一樣.

class AuthInterceptor constructor(private val preferencesUtils: PreferencesUtils) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val userToken = preferencesUtils.userToken
        val newBuilder = chain.request().newBuilder()
        if (userToken != null && userToken.isNotEmpty()) {
            newBuilder.addHeader("Authorization", "token $userToken")
        }
        newBuilder.addHeader("Accept", "application/vnd.github.v3+json")
        val request = newBuilder.build()
        return chain.proceed(request)
    }
}

參考