加入我们,于10月8-10日在纽约市学习有关GraphQL联邦和API平台工程的最新技巧、趋势和新闻。加入我们,共同参加2024年的GraphQL峰会(在纽约市)
文档
免费开始

迁移到 Apollo Kotlin 3.0

从 2.x 版本开始


3.0 使用 Kotlin 重新编写了 Apollo Android 的大部分内部代码。除了其他改进外,它还包括:

  • Kotlin 首选,协程 API
  • 统一的 JVM 和多平台运行时
  • 声明式缓存,@nonnull 客户端 ,性能改进等等...

尽管库的概念大多数相同,但许多 API 已经更改以更好地在 Kotlin 中运行。

本页描述了最重要的更改,以及如何将现有项目从 Apollo Android 2.x 迁移到 Apollo Kotlin 3.x。

您可以在我们的 GitHub 仓库中打开一个issue加入社区或者访问 KotlinLang Slack 中的通道(在这里获取邀请)这里)。

快速路径 🚀

Apollo Kotlin 3 提供了一些辅助工具和兼容模式,以简化从 2.x 版本的迁移过程。为了快速达成运行状态,请按照以下步骤进行。一旦你有了可运行的程序,我们强烈建议迁移到本节下面描述的惯用 Apollo Kotlin 3 版本。在未来版本的 Apollo Kotlin 中将移除兼容助手。全部详情

  1. 更新你的依赖和导入(com.apollographql.apollo com.apollographql.apollo3,详见下文部分)。根据需要移除 apollo-coroutines-supportapollo-android-support
  2. Gradle 配置
apollo {
// Remove this
generateKotlinModels.set(true)
// Add this
useVersion2Compat()
}
  1. 配置:
val client = ApolloClient.builder()
.serverUrl(...)
// Replace:
.addCustomTypeAdapter(CustomType.YOURTYPE, ...)
// With:
.addCustomScalarAdapter(YourType.type, ...)
.build()

全部详情

包名/组 ID/插件 ID

Apollo Kotlin 3.0 使用新的标识符来识别其包名、Gradle 插件 ID 和 Maven 组 ID: com.apollographql.apollo3

此改动避免了依赖冲突,正如在 Java 主要版本更新互操作性政策中所倡导的。它还允许在需要时同时运行版本 2 和版本 3。

在大多数情况下,您可以通过执行查找和替换操作来更新项目中的标识符,将 com.apollographql.apollo 替换为 com.apollographql.apollo3

组 ID

识别 Apollo Kotlin 3.0 相关元数据的 Maven 组 ID 是 artifactscom.apollographql.apollo3

// Replace:
implementation("com.apollographql.apollo:apollo-runtime:$version")
implementation("com.apollographql.apollo:apollo-api:$version")
// With:
implementation("com.apollographql.apollo3:apollo-runtime:$version")
implementation("com.apollographql.apollo3:apollo-api:$version")

Gradle 插件 ID

Apollo Kotlin 3.0 的 Gradle 插件 ID 是 com.apollographql.apollo3

// Replace:
plugins {
id("com.apollographql.apollo") version "$version"
}
// With:
plugins {
id("com.apollographql.apollo3") version "$version"
}

包名

所有 Apollo Kotlin 3.0 类都从 com.apollographql.apollo3 包导入:

// Replace:
import com.apollographql.apollo.ApolloClient
// With:
import com.apollographql.apollo3.ApolloClient

Gradle 配置

任务名称

在Apollo Kotlin 3.x中,Gradle插件发生了显著的变化,现在只为所有Android生成一次模型。如果您之前使用过类似于 "generateDebugServiceApolloSources" 的任务名称,您现在可以去掉Android变体名称,改为使用 "generateServiceApolloSources"。

generateKotlinModels

如果您正在使用Kotlin Gradle插件,Apollo Kotlin 3.0默认会生成Kotlin模型。您现在可以安全地移除此行为:

apollo {
// remove this
generateKotlinModels.set(true)
}

apollo-coroutines-support已移除

Apollo Kotlin 3.x以Kotlin为优先,默认暴露挂起函数。因此,不再需要apollo-coroutines-support

// Remove:
implementation("com.apollographql.apollo:apollo-coroutines-support:$version")

apollo-android-support已移除

Apollo Android 2.x发布了一个小的工件,以支持在特定的Handler上运行回调并将日志写入logcat。

Apollo Kotlin 3.x使用协程并在其API中公开更多信息,因此不再需要日志钩子。如果您使用日志来获取有关缓存命中/未命中的信息,您现在可以通过捕获CacheMissException以更类型化的方式获取相同的信息。

// Remove:
implementation("com.apollographql.apollo:apollo-android-support:$version")

标量映射

为了明确表明自定义映射仅适用于而不是任意类型,customTypeMapping已被替换为mapScalar方法。

apollo {
// Replace
customTypeMapping = [
"GeoPoint" : "com.example.GeoPoint",
"Date" : "com.example.MyDate"
]
// With
mapScalar("GeoPoint", "com.example.GeoPoint")
mapScalar("Date", "com.example.MyDate")
}
apollo {
// Replace
customTypeMapping.set(mapOf(
"GeoPoint" to "com.example.GeoPoint",
"Date" to "com.example.MyDate"
))
// With
mapScalar("GeoPoint", "com.example.GeoPoint")
mapScalar("Date", "com.example.MyDate")
}

指定模式和 .graphql 文件

Apollo Android 2.x 拥有复杂的逻辑来判断使用哪些文件作为输入。例如,它解析 sourceFolder 相对于多个 Android variants 或 kotlin sourceSets,尝试从模式位置获取 文件,反之亦然。这种逻辑在大多数情况下都可行,但在更复杂的场景中会使故障排除变得更加复杂。此外,即使在大多数情况下都使用相同的 .graphql 文件,这也将在不同的源集合对于 GraphQL 编译器进行多次运行。

Apollo Kotlin 3.x 简化了这种设置。每个 Service 只有一个编译。对于 Android 项目, 类只生成一次,然后添加到所有 variants

如果您之前使用 graphqlSourceDirectorySet 显式指定 GraphQL 文件的定位,现在您可以使用 srcDir

apollo {
// Replace
graphqlSourceDirectorySet.srcDirs += "shared/graphql"
// With
srcDir("shared/graphql")
// Replace
graphqlSourceDirectorySet.include("**/*.graphql")
graphqlSourceDirectorySet.exclude("**/schema.graphql")
// With
includes.add("**/*.graphql")
excludes.add("**/schema.graphql")
}

如果你曾依赖模式位置来自动查找 .graphql 文件,你现在也应添加 srcDir() 来显式设置你的 .graphql 文件位置:

apollo {
// Replace
schemaFile.set(file("src/main/graphql-api/schema.graphqls"))
// With
// Keep schemaFile
schemaFile.set(file("src/main/graphql-api/schema.graphqls"))
// explicitly set srcDir
srcDir(file("src/main/graphql-api/"))
}

如果您需要为不同变体不同的 GraphQL ,您可以使用 apollo.createAllAndroidVariantServices.

包名

Apollo Android 2.x 根据GraphQL 操作 和模式文件的路径,以及 packageNamerootPackageName 选项来计算其目标包名。虽然这很灵活,但难以预料最终的包名。

Apollo Kotlin 3.x 默认使用 packageName 选项来使用扁平包名:

apollo {
packageName.set("com.example")
}

生成的类将是

- com.example.SomeQuery
- com.example.fragment.SomeFragment
- com.example.type.SomeInputObject
- com.example.type.SomeEnum
- com.example.type.Types // types is a slimmed down version of the schema

如果您需要在不同的操作文件夹中具有不同的包名,您可以使用以下方式回退到2.x行为:

apollo {
packageNamesFromFilePaths("$rootPackageName")
# If using version 3.1.0+, you will also need useSchemaPackageNameForFragments
useSchemaPackageNameForFragments.set(true)
}

为了更精细的控制,您还可以定义自己的 PackageNameGenerator:

apollo {
packageNameGenerator.set(customPackageNameGenerator)
}

构建器

在 Apollo Android 2.x 中,您会使用 ApolloClient.builder() 方法来实例化一个新的构建器。在3.x中,请使用 ApolloClient.Builder() 构造函数(注意大写 B)。

// Replace
val apolloClient = ApolloClient.builder()
.serverUrl(serverUrl)
// ...other Builder methods
.build()
// With
val apolloClient = ApolloClient.Builder()
.serverUrl(serverUrl)
// ...other Builder methods
.build()

操作API

Apollo Android 2.x 有回调API可能会变得冗长,并需要显式处理取消。

Apollo Kotlin 3.x 提供更简洁的协程API,它通过协程作用域自动处理取消。

此外, mutate 已更名为 mutation,而 subscribe 已更名为 subscription 以保持一致性。

// Replace
apolloClient.query(query).await()
// With
apolloClient.query(query).execute()
// Replace
apolloClient.mutate(query).await()
// With
apolloClient.mutation(query).execute()
// Replace
apolloClient.subscribe(query).toFlow()
// With
apolloClient.subscription(subscription).toFlow()

自定义标量适配器

Apollo Kotlin 3提供了可选的 apollo-adapters 软件包,它包括常见的 类型的适配器,例如:

  • KotlinxInstantAdapter 用于 kotlinx.datetime.Instant ISO8601 日期
  • JavaInstantAdapter 用于 java.time.Instant ISO8601 日期
  • KotlinxLocalDateAdapter 用于 kotlinx.datetime.LocalDate ISO8601 日期
  • JavaLocalDateAdapter 用于 java.time.LocalDate ISO8601 日期
  • KotlinxLocalDateTimeAdapter 用于 kotlinx.datetime.LocalDateTime ISO8601 日期
  • JavaLocalDateTimeAdapter 用于 java.time.LocalDateTime ISO8601 日期
  • JavaOffsetDateTimeAdapter 用于 java.time.OffsetDateTime ISO8601 日期
  • DateAdapter 用于 java.util.Date ISO8601 日期
  • BigDecimalAdapter 用于多平台 com.apollographql.apollo3.adapter.BigDecimal 类,该类存储大数计算值

要将它们包含在内,请将以下依赖项添加到您的gradle文件中

dependencies {
implementation("com.apollographql.apollo3:apollo-adapters:$version")
}

如果上述适配器不符合您的需求,或者您需要对其进行自定义,则可以使用自定义 适配器 API。

自定义标量适配器 API 为了支持可空值和无值以及流使用情况而进行了大量更改。Apollo Kotlin 3 使可能毫无需要在内存中创建中间副本的情况下读写自定义标量。为此,它使用了内部用于解析模型的相同 Adapter API:

// Replace
val dateAdapter = object : CustomTypeAdapter<Date> {
override fun decode(value: CustomTypeValue<*>): Date {
return DATE_FORMAT.parse(value.value.toString())
}
override fun encode(value: Date): CustomTypeValue<*> {
return GraphQLString(DATE_FORMAT.format(value))
}
}
// With
val dateAdapter = object : Adapter<Date> {
override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): Date {
return DATE_FORMAT.parse(reader.nextString())
}
override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: Date) {
writer.value(DATE_FORMAT.format(value))
}
}

JsonReaderJsonWriter API 与您在 Moshi 中找到的 API 类似。JsonReaderJsonWriter 是具有状态的 API,您需要按照从 JSON 流接收到的顺序处理 JSON 属性。

// Use AnyAdapter to convert between JsonReader/JsonWriter and a Kotlin Any value
val geoPointAdapter = object : Adapter<GeoPoint> {
override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): GeoPoint {
val map = AnyAdapter.fromJson(reader) as Map<String, Double>
return GeoPoint(map["latitude"] as Double, map["longitude"] as Double)
}
override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: GeoPoint) {
val map = mapOf(
"latitude" to value.latitude,
"longitude" to value.longitude
)
AnyAdapter.toJson(writer, map)
}
}

定义完适配器后,您需要将其注册到您的 ApolloClient 实例。为此,为每个适配器调用一次 ApolloClient.Builder.addCustomScalarAdapter

// Replace
val apolloClient = apolloClientBuilder.addCustomTypeAdapter(CustomType.DATE, dateAdapter).build()
// With
val apolloClient = apolloClientBuilder.addCustomScalarAdapter(Date.type, dateAdapter).build()

此方法需要一个由 Types 生成的高类型安全类及其相应的适配器。

代码生成

Apollo Kotlin 3.x 提供了 3 种代码生成选项:

  • 基于操作: Kotlin 模型映射发送的 GraphQL 操作。
  • 基于响应: Kotlin 模型映射接收的 JSON 响应。
  • 兼容性: 与 Apollo Kotlin 2.x 兼容。

兼容codegen会复制一些并引入一个额外的.fragments字段。虽然这是从2.x迁移的简单方法,但一旦您的项目以compat模式运行,我们建议迁移到operationBased

operationBasedcodegen更简单,消除了一些字段,并去掉了中间的.fragments字段。

以下是一个示例:

fragment humanDetails on Human {
height
}
query GetHero {
hero {
name
... on Droid {
primaryFunction
}
...humanDetails
}
}

您可以像这样迁移到operationBased:

// parent fields are not collected in inline fragments
// Replace
hero.asDroid?.name
// With
hero.name
// because parent fields are not collected, inline fragments
// are now named "OnFoo" instead of "AsFoo"
// Replace
hero.asDroid?.primaryFunction
// With
hero.onDroid?.primaryFunction
// there is no .fragment synthetic field for named fragments
// Replace
hero.fragments?.humanDetails?.height
// With
hero.humanDetails?.height

我们推荐大多数项目使用operationBasedcodegen。

要进一步了解,如果您熟悉operationBasedcodegen,您可以在设计文档中了解更多关于不同codegen(包括使用responseBased的权衡)的信息。

标准化缓存

The Apollo Android 2.x runtime has a dependency on the normalized cache APIs, and it's possible to call cache methods even if no cache implementation is in the classpath.

The Apollo Kotlin 3.x runtime is more modular and doesn't know anything about normalized cache by default. To add normalized cache support, add the dependencies to your gradle file:

配置

dependencies {
// Replace
implementation("com.apollographql.apollo:apollo-normalized-cache:$version") // for memory cache
implementation("com.apollographql.apollo:apollo-normalized-cache-sqlite:$version") // for SQL cache
// With
implementation("com.apollographql.apollo3:apollo-normalized-cache:$version") // for memory cache
implementation("com.apollographql.apollo3:apollo-normalized-cache-sqlite:$version") // for SQL cache
}
// Replace
val cacheFactory = LruNormalizedCacheFactory(
EvictionPolicy.builder().maxSizeBytes(10 * 1024 * 1024).build()
)
val apolloClient = ApolloClient.builder()
.serverUrl("https://...")
.normalizedCache(cacheFactory)
.build()
// With
val cacheFactory = MemoryCacheFactory(maxSizeBytes = 10 * 1024 * 1024)
val apolloClient = ApolloClient.Builder()
.serverUrl("https://...")
.normalizedCache(cacheFactory)
.build()

配置fetch策略现在是在ApolloCall实例上进行的:

// Replace
val response = apolloClient.query(query)
.toBuilder()
.responseFetcher(ApolloResponseFetchers.CACHE_FIRST)
.build()
.await()
// With
val response = apolloClient.query(request)
.fetchPolicy(CacheFirst)
.execute()

观察者

观察者的默认refetch策略现在是CacheOnly而不是CACHE_FIRST。为了保持行为不变,请在您的观察者上设置refetchPolicy

val response = apolloClient.query(query)
.watcher()
.toFlow()
// With
val response = apolloClient.query(query)
.refetchPolicy(CacheFirst)
.watch()

CacheKeyResolver

CacheKeyResolver API已被划分为两个不同的API:

  • CacheKeyGenerator.cacheKeyForObject
    • 接受JSON数据作为输入,为一个对象返回一个唯一ID。
    • 处理网络请求后 使用。
    • 在写入缓存时 使用。
  • CacheKeyResolver.cacheKeyForField
    • 接受一个GraphQL 字段和操作作为输入,并为该字段生成一个ID。
    • 在处理网络请求之前使用
    • 读取缓存时使用

以前,这两种方法都包含在CacheResolver类中,尽管底层代码路径非常不同。通过分离它们,使它们更加明确,并有可能仅实现其中之一。

从高层次来看,

  • fromFieldRecordSet 已更名为 CacheKeyGenerator.cacheKeyForObject
  • fromFieldArguments 已更名为 CacheKeyResolver.cacheKeyForField
  • 现在,CacheKey 返回值现在是可空的,CacheKey.NONE 已用null 替换。
// Replace
val resolver: CacheKeyResolver = object : CacheKeyResolver() {
override fun fromFieldRecordSet(field: ResponseField, recordSet: Map<String, Any>): CacheKey {
return CacheKey.from(recordSet["id"] as String)
}
override fun fromFieldArguments(field: ResponseField, variables: Operation.Variables): CacheKey {
return CacheKey.from(field.resolveArgument("id", variables) as String)
}
}
val apolloClient = ApolloClient.builder()
.serverUrl("https://...")
.normalizedCache(cacheFactory, resolver)
.build()
// With
val cacheKeyGenerator = object : CacheKeyGenerator {
override fun cacheKeyForObject(obj: Map<String, Any?>, context: CacheKeyGeneratorContext): CacheKey? {
return obj["id"]?.toString()?.let { CacheKey(it) } ?: TypePolicyCacheKeyGenerator.cacheKeyForObject(obj, context)
}
}
val cacheKeyResolver = object : CacheKeyResolver() {
override fun cacheKeyForField(field: CompiledField, variables: Executable.Variables): CacheKey? {
return (field.resolveArgument("id", variables) as String?)?.let { CacheKey(it) }
}
}
val apolloClient = ApolloClient("https://").normalizedCache(
normalizedCacheFactory = cacheFactory,
cacheKeyGenerator = cacheKeyGenerator,
cacheResolver = cacheKeyResolver
)

缓存缺失现在总是抛出异常

在Apollo Android 2中,具有CacheOnly 策略的缓存缺失返回一个包含response.data = nullApolloResponse。这与将缓存缺失视为错误的CacheFirst 策略不一致。

在Apollo Android 3中,调用ApolloCall.execute()保证总是返回一个有效(可能是部分)的ApolloResponse或抛出异常。

如果您有任何CacheOnly 查询,请确保捕获其结果:

try {
apolloClient.query(query)
.fetchPolicy(CacheOnly)
} catch (e: ApolloException) {
// handle error
}

HTTP缓存

要添加http缓存支持,请将依赖项添加到您的gradle文件中

dependencies {
// Add
implementation("com.apollographql.apollo3:apollo-http-cache:$version") // Gives access to `httpCache` and `httpFetchPolicy`
}

同样,HTTP缓存可以通过扩展函数进行配置

// Replace
val cacheStore = DiskLruHttpCacheStore()
val apolloClient = ApolloClient.builder()
.serverUrl("/")
.httpCache(ApolloHttpCache(cacheStore))
.build()
// With
val apolloClient = ApolloClient.Builder()
.serverUrl("https://...")
.httpCache(File(cacheDir, "apolloCache"), 1024 * 1024)
.build()

现在在ApolloCall 实例上配置HTTP抓取策略:

// Replace
val response = apolloClient.query(query)
.toBuilder()
.httpCachePolicy(HttpCachePolicy.CACHE_FIRST)
.build()
.await()
// With
val response = apolloClient.query(request)
.httpFetchPolicy(CacheFirst)
.execute()

为了与标准化缓存保持一致,默认的httpFetchPolicy现在是HttpFetchPolicy.CacheFirst。为了保持与2.0相同的默认行为,请使用HttpFetchPolicy.NetworkOnly

可选值

Optional

Apollo Kotlin 区分了null值和不存在值。

Apollo Android 2.x 使用Input表示输入类型的可选(可能为可空的)值。

Apollo Kotlin 3.x使用Optional以实现对可能的输入类型以外的使用(例如,字段可以使用@optional标记为可选,详情请见https://github.com/apollographql/apollo-android/blob/5c1ff82ccaded93ae7126cedc6d7835e63fed75a/apollo-compiler/src/main/resources/apollo.graphqls#L6)。

Optional是一个封闭类,因此when语句不需要else分支。

// Replace
Input.fromNullable(value)
// With
Optional.Present(value)
// Replace
Input.absent()
// With
Optional.Absent
// Replace
Input.optional(value)
// With
Optional.presentIfNotNull(value)

非可选变量的生成

默认情况下,GraphQL规范将可为空的变量视为可选,因此可以在运行时省略它们。然而,在实践中,这很少使用,并且会使操作声明更冗长。

因此,Apollo Kotlin 3.x提供了移除Optional包装器的机制,这使得构建带有可为空变量的查询更加直接。

当启用时,此新行为仅适用于变量仍使用Optional,因为省略具体的输入字段是常见的情况。

全局在Gradle配置中省略可选变量:

apollo {
// ...
generateOptionalOperationVariables.set(false)
}

如果您仍然需要在某些地方省略,您可以选择使用Optional包装器与@optional指令来启用它:

query GetHero($id: String @optional) {
hero(id: $id)
}

更多详细信息请点击此处

枚举

Apollo Android 2.x总是将枚举和枚举值名称转换为大写。

Apollo Kotlin 3.x使用枚举以及枚举值名称的方案大小写。这允许定义具有不同大小写的多个枚举值:

# This now generates valid Kotlin code
enum Direction {
left @deprecated("use LEFT instead")
LEFT,
RIGHT
}

有关更多详细信息,请参阅#3035

IdlingResource

在Apollo Android 2.x中,您可以将ApolloClient传递给ApolloIdlingResource.create(),然后ApolloClient将被修改以注册空闲回调。

在 Apollo Kotlin 3.x 中,一旦实例化 ApolloClient,它就是不可变的,因此一旦实例化之后就不能再注册回调或拦截器。相反,您可以首先创建您的 ApolloIdlingResource,然后将它传递给您的 ApolloClient.Builder,如下所示:

// Replace
val idlingResource = ApolloIdlingResource.create("ApolloIdlingResource", apolloClient)
IdlingRegistry.getInstance().register(idlingResource)
// With
val idlingResource = ApolloIdlingResource("ApolloIdlingResource")
IdlingRegistry.getInstance().register(idlingResource)
val apolloClient = ApolloClient.Builder()
.serverUrl("https://example.com/graphql")
.idlingResource(idlingResource)
.build()

BigDecimal

默认情况下,Apollo Android 2.x 在内部将所有数字映射到一个自定义的 BigDecimal 值。

出于性能考虑,Apollo Kotlin 3.x 在可能的情况下使用原始类型,并将 BigDecimal 移动到 apollo-adapters 库中。

如果您在您的模式中使用自定义 scalars 来表示大数,那么现在您应该明确地将它们添加到您的 Gradle 配置中:

dependencies {
implementation("com.apollographql.apollo3:apollo-adapters:x.y.z")
}
apollo {
mapScalar(
"Decimal",
"com.apollographql.apollo3.adapter.BigDecimal",
"com.apollographql.apollo3.adapter.BigDecimalAdapter"
)
}

如果您没有使用大数自定义 scalars,但是您正在定义自己的适配器,您可能仍然受到影响。在这种情况下,您可能收到的将是 IntDouble 而不是 BigDecimal

val customTypeAdapter = object: CustomTypeAdapter<Address> {
override fun decode(value: CustomTypeValue<*>): Address {
check (value is CustomTypeValue.GraphQLJsonObject)
val street = value.value["street"] as String
// BigDecimal is not exposed anymore
// Replace
// val number = value.value["number"] as BigDecimal
// With
val number = value.value["number"] as Int
return Address(street, number)
}
}

默认情况下,如果数字不适合在 Int 中,它将被映射到 IntDouble。如果数字也不适合在 Double 中,它将回退到一个包含数字的字符串表示的 JsonNumber

ApolloLogger

Apollo Android 2.x 有一个 ApolloLogger 接口。其主要用例之一是记录缓存未命中。

Apollo Android 3.x 删除了这个接口,并使用 API 暴露了这个信息。API 提供了更结构化和可维护的方式来暴露数据。

对于自定义日志记录,您可以现在使用一个 ApolloInterceptor

对于缓存未命中,您可以使用便利方法 ApolloClient.Builder.logCacheMisses()

val apolloClient = ApolloClient.Builder()
.serverUrl(mockServer.url())
.logCacheMisses() // Put this before setting up your normalized cache
.normalizedCache(MemoryCacheFactory())
.build()

Subscriptions

Apollo Android 2.x 有一个 SubscriptionManager 类。这个类公开了很多关于 Websocket 状态管理的方法和数据。虽然非常灵活,但难以维护和演进。

Apollo Android 3.x instead 使用 WebsocketNetworkTransport 来暴露一个简化的 API:

  • protocolFactory 允许使用 graphql-ws 或 AppSync(或您的自定义之一)作为较低级别的协议,而不是默认协议。
  • reopenWhen 允许在出现网络错误或其他错误的情况下自动重新订阅。

如果您之前使用过 apolloClient.subscriptionManager.reconnect() 来强制 Websocket 重连(例如发送新的认证参数),现在您可以调用 apolloClient.subscriptionNetworkTransport.closeConnection(<your exception>):这会表现得好像发生了网络错误,并且您可以通过 reopenWhen 来对这种错误做出响应。

如果您之前正在使用 subscriptionConnectionParams 对您的 进行身份验证,现在您可以使用 wsProtocol 与一个包含在 SubscriptionWsProtocol.Factory 中的 connectionPayload。更多信息请在 WebSockets 身份验证 中查看。

如果您觉得 SubscriptionManager 中缺少某些 API,请 联系我们,以便我们讨论最佳添加方法。

下载模式

由于无法可靠地确定 Gradle 当前工作目录,downloadApolloSchema 任务现在使用相对于根项目目录的路径:

# schema is now interpreted relative to the root project directory and
# not the current working directory anymore. This example assumes there
# is a 'app' module that applies the apollo plugin
./gradlew downloadApolloSchema \
--endpoint="https://your.domain/graphql/endpoint" \
--schema="app/src/main/graphql/com/example/schema.graphqls"

如果您在 Gradle 脚本中配置了 introspection {}registry {} 块,现在应该使用 downloadServiceApolloSchemaFromIntrospectiondownloadServiceApolloSchemaFromRegistry

OkHttp

由于 3.x 是多平台优先的,运行时抽象了 OkHttp,位于 HttpEngine API 之下。如果您依赖于 OkHttpExecutionContext,您现在可以使用 HttpInfo 来访问 HTTP 响应代码和头信息:

// Replace
response.executionContext[OkHttpExecutionContext].response.code
// With
response.executionContext[HttpInfo]?.statusCode

在未使用运行时的情况下使用模型

API 已更新以允许流式使用情况。要组合请求体

// Replace
val request = query.composeRequestBody()
// With
val request = buildJsonString {
query.composeJsonRequest(this, CustomScalarAdapters.Empty)
}

要解析响应体

// Replace
val response = query.parse(bufferedSource);
// With
val response = query.parseJsonResponse(bufferedSource);

refetchQueries()

Apollo Android 2.x 暴露了 ApolloCall.Builder.refetchQueries(List<Query>)。这用于在影响其他查询的 后从网络获取新值。这提供了对错误处理、缓存或并发性的有限控制。

Apollo Kotlin 3.x 暴露了一个协程 API,便于在不使用库的情况下实现类似的功能。协程使得调用链式、错误重试以及改变调度程序变得容易。对于简单版本,你可以这样做:

suspend fun <MutationData: Mutation.Data> mutation(mutation: Mutation<MutationData>, vararg refetchQueries: Query<*>) {
apolloClient.mutation(mutation).execute()
refetchQueries.forEach {
apolloClient.query(it).execute()
}
}

如果您想将更新绑定到 ApolloClient 的作用域中,您可以使用

suspend fun <MutationData: Mutation.Data> mutation(mutation: Mutation<MutationData>, vararg refetchQueries: Query<*>) {
apolloClient.mutation(mutation).execute()
apolloClient.executionContext[ConcurrencyInfo]!!.coroutineScope.launch {
refetchQueries.forEach {
apolloClient.query(it).execute()
}
}
}

尚未计划在库中添加 refetchQueries()

下一步
入门
评价文章评价在GitHub上编辑编辑论坛Discord

©2024Apollo Graph Inc.,或称Apollo GraphQL。

隐私政策

公司