从10月8日至10日与我们在纽约市相聚,了解关于 GraphQL Federation 和 API 平台工程的最新的技巧、趋势和新闻。加入我们在纽约市举办的 2024 年 GraphQL summit。
文档
免费开始
您正在查看此软件旧版本的文档。 切换到最新稳定版本。

迁移到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 仓库中提交问题, 加入社区访问 KotlinLang Slack 的频道(在此处获取邀请)).

快速通道 🚀

Apollo Kotlin 3 提供了一些辅助器和兼容模式,以简化从 2.x 版本的迁移。为了快速达到工作状态,请按照以下步骤操作。一旦你有了一个工作中的应用程序,我们强烈建议您迁移到下面的使用说明中的 Apollo Kotlin 3 语法,兼容辅助器将在 Apollo Kotlin 的未来版本中删除。所有详细信息部分

  1. 更新依赖和导入(com.apollographql.apollocom.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 是 工件,它为 com.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" 这样的任务名称,现在您可以使用 "generateServiceApolloSources" 而不是 Android 变体名称。

生成Kotlin模型

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 变体 或 kotlin 源集,尝试从模式位置获取 文件,反之亦然。这种逻辑在大多数情况下都可行,但在更复杂的情况下,会遇到更复杂的调试问题。此外,它会在不同的源集中多次运行 GraphQL 编译器,即使在大多数情况下,使用的 .graphql 文件是相同的。

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

如果您之前使用了 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 创建每个 Android 变体的多个服务。

包名

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 已更名为 mutationsubscribe 已更名为 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,它们要求您按顺序处理来自 JSON 流的 JSON 属性。如果您愿意,还可以将 JSON 缓冲到未类型化的 Any? 值中,该值表示 json,并使用 AnyAdapter 对其进行解码/编码:

// 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 种代码生成选项:

  • operationBased: Kotlin 模型映射发送的 GraphQL 操作。
  • responseBased: Kotlin 模型映射接收的 Json 响应。
  • compat: 与 Apollo Kotlin 2.x 的兼容性

兼容代码生成中,一些字段被重复,并引入了一个额外的字段。虽然这是一个方便从2.x迁移的方法,但我们建议您的项目以兼容模式运行后,迁移到基于操作

基于操作的代码生成更简单,减少了某些字段,并删除了中间的:.fragments字段

给定以下

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

您可以像这样迁移到 基于操作

// 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

我们推荐对大多数项目使用 基于操作代码生成。

如果您熟悉 基于操作代码生成,可以在设计文档中了解有关不同代码生成器(包括使用 基于响应的权衡)的更多信息。

规范化缓存

Apollo Android 2.x运行时依赖于规范化缓存API,即使在类路径中没有实现缓存,也可以调用缓存方法。

Apollo Kotlin 3.x运行时更加模块化,默认情况下不知道任何东西关于规范化缓存。要添加规范化缓存支持,将依赖项添加到您的gradle文件中:

配置

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 policy是在ApolloCall实例上进行的:

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

观察者

观察者现在默认使用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的返回值现在是nullable的,并且将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

可选值

The Optional class

Apollo Kotlin区分空值和不存在值。

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

Apollo Kotlin 3.x 使用 Optional 来代替,这样以后它可以在除了输入类型以外的位置使用,例如,可以使用 @optional

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 包装器,这使得构建包含可空变量的查询更加直接。

启用后,这种新行为仅适用于变量。

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

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

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

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

更多信息请参阅 这里

枚举

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

Apollo Kotlin 3.x 使用 schema case 上下文为枚举和枚举值名称,这允许定义多个具有不同 case 的枚举值:

# 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模块。

如果您在您的模式中使用了自定义big decimal标量,现在应该明确地将它们添加到您的Gradle配置中:

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

如果您没有使用big decimal自定义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使用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 是多平台优先的,因此运行时在 HttpEngine API 的背后抽象化了 OkHttp。如果您依赖于 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()

Previous
开始使用
Next
0. 简介
评价文章评价在GitHub上编辑Edit论坛Discord

©2024Apollo Graph Inc.,商业名称:Apollo GraphQL。

隐私政策

公司

获取联系信息