Apollo Kotlin 中的自定义标量类型
除了其内置标量类型 (Int
, String
等.), GraphQL 支持自定义标量。例如,您的模式可能定义了一个用于 Long
, Date
, BigDecimal
或 GeoPoint
的自定义标量。
定义类映射
在与您的 Apollo Kotlin 应用中的自定义 标量 进行交互时,您需要在您的 build.gradle[.kts]
文件中定义一个映射。这将告诉 Apollo Kotlin 使用哪个类来表示您 schema 中的每个自定义 标量。
apollo {service("service") {mapScalar("GeoPoint", "com.example.GeoPoint")// Shortcuts exist for standard types - equivalent to mapScalar("Long", "kotlin.Long")mapScalarToKotlinLong("Long")}}
如果需要的话,您也可以用内置 标量(如 ID
)来覆盖其默认类型。
定义类适配器
您用来表示自定义 标量的每个类也需要一个 适配器,用于将其转换为从网络发送的 JSON 格式。
每个适配器都需要一个 fromJson
函数。如果您的应用将自定义 标量作为 GraphQL 参数 传递,则需要一个 toJson
函数。
这是一个用于 GeoPoint
自定义 标量的适配器:
class GeoPoint(val latitude: Double, val longitude: Double)val geoPointAdapter = object : Adapter<GeoPoint> {override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): GeoPoint {var latitude: Double? = nullvar longitude: Double? = nullreader.beginObject()while(reader.hasNext()) {when (reader.nextName()) {"latitude" -> latitude = reader.nextDouble()"longitude" -> longitude = reader.nextDouble()}}reader.endObject()// fromJson can throw on unexpected data and the exception will be wrapped in a// ApolloParseExceptionreturn GeoPoint(latitude!!, longitude!!)}// If you do not expect your scalar to be used as input, you can leave this method as TODO()override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: GeoPoint) {writer.beginObject()writer.name("latitude").value(value.latitude)writer.name("longitude").value(value.longitude)writer.endObject()}}
如果您更喜欢使用 Map
, Apollo Kotlin 提供了 AnyAdapter
,它支持将 String
、Int
、Double
、Boolean
、List
和 Map
进行适配。您可以在中间步骤中使用它:
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)}}
此解决方案更简洁,但性能略低。
注册适配器
定义完适配器后,您需要注册它们。这可以在 build.gradle[.kts]
文件中完成,或者在运行时完成。
build.gradle[.kts]
可以为 mapScalar
传递第三个参数来指定要使用的适配器:
apollo {service("service") {mapScalar("GeoPoint", "com.example.GeoPoint", "com.example.Adapters.geoPointAdapter")}}
生成的代码中直接复制给定的表达式。因此,可以传递以下任何一种
- 实例化表达式,如
"com.example.GeoPointAdapter()"
- 单例引用,如
"com.example.GeoPointAdapter"
- 函数调用,如
"com.example.Adapters.getGeoPointAdapter()"
确保传递包括包在内的完整类名,因为不会自动生成导入。
在运行时
您还可以通过调用 ApolloClient.Builder.addCustomScalarAdapter
为每个适配器在您的 ApolloClient
实例上注册适配器:
val apolloClient = ApolloClient.Builder().serverUrl("https://").addCustomScalarAdapter(GeoPoint.type, geoPointAdapter).build()
此方法接收从 Types
生成的类型安全的类及其对应的适配器。
如果您找不到 Types
,请在构建项目中触发代码生成。
由 Apollo 提供的适配器
以下内置适配器可以与常见的自定义 标量 类型一起使用:
适配器 | 描述 |
---|---|
com.apollographql.apollo3.api.FloatAdapter | 转换 kotlin.Float /java.lang.Float |
com.apollographql.apollo3.api.LongAdapter | 转换 kotlin.Long /java.lang.Long |
除此之外,com.apollographql.apollo3:apollo-adapters
软件包还提供了以下适配器:
适配器 | 描述 |
---|---|
com.apollographql.apollo3.adapter.KotlinxInstantAdapter | 用于 kotlinx.datetime.Instant ISO8601 日期 |
com.apollographql.apollo3.adapter.JavaInstantAdapter | 用于 java.time.Instant ISO8601 日期 |
com.apollographql.apollo3.adapter.KotlinxLocalDateAdapter | 用于 kotlinx.datetime.LocalDate ISO8601 日期 |
com.apollographql.apollo3.adapter.JavaLocalDateAdapter | 用于 java.time.LocalDate ISO8601 日期 |
com.apollographql.apollo3.adapter.KotlinxLocalDateTimeAdapter | 用于 kotlinx.datetime.LocalDateTime ISO8601 日期 |
com.apollographql.apollo3.adapter.JavaLocalDateTimeAdapter | 用于 java.time.LocalDateTime ISO8601 日期 |
com.apollographql.apollo3.adapter.KotlinxLocalTimeAdapter | 用于 kotlinx.datetime.LocalTime ISO8601 日期 |
com.apollographql.apollo3.adapter.JavaLocalTimeAdapter | 用于 java.time.LocalTime ISO8601 日期 |
com.apollographql.apollo3.adapter.JavaOffsetDateTimeAdapter | 用于 java.time.OffsetDateTime ISO8601 日期 |
com.apollographql.apollo3.adapter.DateAdapter | 用于 java.util.Date ISO8601 日期 |
com.apollographql.apollo3.adapter.BigDecimalAdapter | 用于包含大数值的 Multiplatform com.apollographql.apollo3.adapter.BigDecimal 类 |
注意:由于一些适配器使用了 kotlinx.datetime
(它本身又使用了 java.time
),您需要在 Android API 级别 < 26 上启用 核心库降级。
例如,要使用 DateAdapter
,请按照以下方式配置您的 Gradle 脚本:
dependencies {implementation("com.apollographql.apollo3:apollo-adapters:3.8.5")}apollo {service("service") {mapScalar("Date", "java.util.Date", "com.apollographql.apollo3.adapter.DateAdapter")}}