Apollo Kotlin中的自定义标量类型
除了它的内建标量类型(Int
, String
等),支持定义 GraphQL 支持 自定义标量。例如,您的架构可能为 标量 定义一个自定义标量,例如为 Long
,Date
,BigDecimal
或 GeoPoint
。
定义类映射
为了与您的 Apollo Kotlin 应用中的自定义 标量 进行交互,您需要在您的 build.gradle[.kts]
文件中定义一组映射。这会告诉 Apollo Kotlin 如何表示您的架构中每个自定义 标量。
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://example.com/graphql").addCustomScalarAdapter(GeoPoint.type, geoPointAdapter).build()
此方法接受来自 Types
的类型安全生成类及其对应的适配器。
如果您找不到 Types
,请构建项目以触发代码生成。
内置适配器
apollo-api
提供了以下内置适配器:
适配器 | 描述 |
---|---|
com.apollographql.apollo.api.StringAdapter | 将 kotlin.String /java.lang.String 转换为/from |
com.apollographql.apollo.api.IntAdapter | 将 kotlin.Int /java.lang.Int 转换为/from |
com.apollographql.apollo.api.BooleanAdapter | 将 kotlin.Boolean /java.lang.Boolean 转换为/from |
com.apollographql.apollo.api.DoubleAdapter | 将 kotlin.Double /java.lang.Double 转换为/from |
com.apollographql.apollo.api.FloatAdapter | 将 kotlin.Float /java.lang.Float 转换为/from |
com.apollographql.apollo.api.LongAdapter | 将 kotlin.Long /java.lang.Long 转换为/from |
com.apollographql.apollo.api.AnyAdapter | 将 kotlin.Any /java.lang.Object 转换为/from |
附加适配器
日期和大数的附加适配器可在以下地址找到:https://github.com/apollographql/apollo-kotlin-adapters