Skip to content

Commit 1804e6a

Browse files
authored
[client] update ScalarConverter to accept any objects (#819)
* [client] update ScalarConverter to accept any objects Custom GraphQL scalars can be serialized as any of the other built-in scalars (i.e. int, float, etc). Changed method signatures to accept `Any` when converting to scalar, and produce `Any` when generating JSON value. * update docs to match change to any
1 parent f114833 commit 1804e6a

File tree

8 files changed

+43
-25
lines changed

8 files changed

+43
-25
lines changed

clients/graphql-kotlin-client/src/main/kotlin/com/expediagroup/graphql/client/converter/ScalarConverter.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ package com.expediagroup.graphql.client.converter
2222
interface ScalarConverter<T> {
2323

2424
/**
25-
* Deserialize raw JSON String value to a typesafe value.
25+
* Deserialize raw JSON value to a typesafe value.
2626
*/
27-
fun toScalar(rawValue: String): T
27+
fun toScalar(rawValue: Any): T
2828

2929
/**
30-
* Serialize typesafe scalar value to a raw JSON string.
30+
* Serialize typesafe scalar value to a raw JSON value.
3131
*/
32-
fun toJson(value: T): String
32+
fun toJson(value: T): Any
3333
}

docs/client/client-customization.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,13 @@ val customObjectMapper = jacksonObjectMapper()
150150
val client = GraphQLClient(url = URL("http://localhost:8080/graphql"), mapper = customObjectMapper)
151151
```
152152

153-
## Deprecated Field Usage
153+
## Deprecated Field Usage
154154

155155
Build plugins will automatically fail generation of a client if any of the specified query files are referencing
156156
deprecated fields. This ensures that your clients have to explicitly opt-in into deprecated usage by specifying
157157
`allowDeprecatedFields` configuration option.
158158

159-
## Custom GraphQL Scalars
159+
## Custom GraphQL Scalars
160160

161161
By default, custom GraphQL scalars are serialized and [type-aliased](https://kotlinlang.org/docs/reference/type-aliases.html)
162162
to a String. GraphQL Kotlin plugins also support custom serialization based on provided configuration.
@@ -171,8 +171,8 @@ import com.expediagroup.graphql.client.converter.ScalarConverter
171171
import java.util.UUID
172172

173173
class UUIDScalarConverter : ScalarConverter<UUID> {
174-
override fun toScalar(rawValue: String): UUID = UUID.fromString(rawValue)
175-
override fun toJson(value: UUID): String = value.toString()
174+
override fun toScalar(rawValue: Any): UUID = UUID.fromString(rawValue.toString())
175+
override fun toJson(value: UUID): Any = value.toString()
176176
}
177177
```
178178

@@ -189,6 +189,4 @@ graphql {
189189
}
190190
```
191191

192-
See [Gradle](../plugins/gradle-plugin.md)
193-
and [Maven](../plugins/maven-plugin.md)
194-
plugin documentation for additional details.
192+
See [Gradle](../plugins/gradle-plugin.md) and [Maven](../plugins/maven-plugin.md) plugin documentation for additional details.

examples/spring/src/main/kotlin/com/expediagroup/graphql/examples/hooks/CustomSchemaGeneratorHooks.kt

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ package com.expediagroup.graphql.examples.hooks
1818

1919
import com.expediagroup.graphql.directives.KotlinDirectiveWiringFactory
2020
import com.expediagroup.graphql.hooks.SchemaGeneratorHooks
21+
import graphql.Scalars
2122
import graphql.language.StringValue
2223
import graphql.schema.Coercing
24+
import graphql.schema.CoercingParseLiteralException
25+
import graphql.schema.CoercingParseValueException
26+
import graphql.schema.CoercingSerializeException
2327
import graphql.schema.GraphQLScalarType
2428
import graphql.schema.GraphQLType
2529
import org.springframework.beans.factory.BeanFactoryAware
2630
import reactor.core.publisher.Mono
31+
import java.math.BigDecimal
2732
import java.util.UUID
2833
import kotlin.reflect.KClass
2934
import kotlin.reflect.KType
@@ -39,6 +44,7 @@ class CustomSchemaGeneratorHooks(override val wiringFactory: KotlinDirectiveWiri
3944
*/
4045
override fun willGenerateGraphQLType(type: KType): GraphQLType? = when (type.classifier) {
4146
UUID::class -> graphqlUUIDType
47+
BigDecimal::class -> Scalars.GraphQLBigDecimal
4248
else -> null
4349
}
4450

@@ -68,16 +74,24 @@ internal val graphqlUUIDType = GraphQLScalarType.newScalar()
6874
.build()
6975

7076
private object UUIDCoercing : Coercing<UUID, String> {
71-
override fun parseValue(input: Any?): UUID = UUID.fromString(
72-
serialize(
73-
input
74-
)
75-
)
77+
override fun parseValue(input: Any): UUID = runCatching {
78+
UUID.fromString(serialize(input))
79+
}.getOrElse {
80+
throw CoercingParseValueException("Expected valid UUID but was $input")
81+
}
7682

77-
override fun parseLiteral(input: Any?): UUID? {
83+
override fun parseLiteral(input: Any): UUID? {
7884
val uuidString = (input as? StringValue)?.value
79-
return UUID.fromString(uuidString)
85+
return runCatching {
86+
UUID.fromString(uuidString)
87+
}.getOrElse {
88+
throw CoercingParseLiteralException("Expected valid UUID literal but was $uuidString")
89+
}
8090
}
8191

82-
override fun serialize(dataFetcherResult: Any?): String = dataFetcherResult.toString()
92+
override fun serialize(dataFetcherResult: Any): String = runCatching {
93+
dataFetcherResult.toString()
94+
}.getOrElse {
95+
throw CoercingSerializeException("Data fetcher result $dataFetcherResult cannot be serialized to a String")
96+
}
8397
}

examples/spring/src/main/kotlin/com/expediagroup/graphql/examples/query/ScalarQuery.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import com.expediagroup.graphql.spring.operations.Mutation
2121
import com.expediagroup.graphql.spring.operations.Query
2222
import com.expediagroup.graphql.scalars.ID
2323
import org.springframework.stereotype.Component
24+
import java.math.BigDecimal
2425
import java.util.UUID
26+
import kotlin.random.Random
2527

2628
/**
2729
* Simple query that exposes custom scalar.
@@ -39,6 +41,9 @@ class ScalarQuery : Query {
3941

4042
@GraphQLDescription("generates random GraphQL ID")
4143
fun generateRandomId() = ID(UUID.randomUUID().toString())
44+
45+
@GraphQLDescription("generates random BigDecimal")
46+
fun generateRandomBigDecimal(): BigDecimal = BigDecimal(Random.nextLong())
4247
}
4348

4449
@Component

plugins/graphql-kotlin-gradle-plugin/src/test/resources/mocks/UUIDScalarConverter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import com.expediagroup.graphql.client.converter.ScalarConverter
44
import java.util.UUID
55

66
class UUIDScalarConverter : ScalarConverter<UUID> {
7-
override fun toScalar(rawValue: String): UUID = UUID.fromString(rawValue)
8-
override fun toJson(value: UUID): String = value.toString()
7+
override fun toScalar(rawValue: Any): UUID = UUID.fromString(rawValue.toString())
8+
override fun toJson(value: UUID): Any = value.toString()
99
}

plugins/graphql-kotlin-maven-plugin/src/integration/complete-setup/src/main/kotlin/com/example/UUIDScalarConverter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import com.expediagroup.graphql.client.converter.ScalarConverter
44
import java.util.UUID
55

66
class UUIDScalarConverter : ScalarConverter<UUID> {
7-
override fun toScalar(rawValue: String): UUID = UUID.fromString(rawValue)
8-
override fun toJson(value: UUID): String = value.toString()
7+
override fun toScalar(rawValue: Any): UUID = UUID.fromString(rawValue.toString())
8+
override fun toJson(value: UUID): Any = value.toString()
99
}

plugins/graphql-kotlin-plugin-core/src/main/kotlin/com/expediagroup/graphql/plugin/generator/types/generateGraphQLCustomScalarTypeSpec.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ internal fun generateGraphQLCustomScalarTypeSpec(context: GraphQLClientGenerator
7171
FunSpec.builder("create")
7272
.addAnnotation(JsonCreator::class.java)
7373
.jvmStatic()
74-
.addParameter("rawValue", String::class)
74+
.addParameter("rawValue", Any::class)
7575
.addStatement("return %L(%N.toScalar(rawValue))", customScalarName, converter)
7676
.build()
7777
)

plugins/graphql-kotlin-plugin-core/src/test/kotlin/com/expediagroup/graphql/plugin/generator/types/GenerateGraphQLCustomScalarTypeSpecIT.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class GenerateGraphQLCustomScalarTypeSpecIT {
3535
import com.expediagroup.graphql.types.GraphQLResponse
3636
import com.fasterxml.jackson.annotation.JsonCreator
3737
import com.fasterxml.jackson.annotation.JsonValue
38+
import kotlin.Any
3839
import kotlin.String
3940
import kotlin.jvm.JvmStatic
4041
@@ -61,7 +62,7 @@ class GenerateGraphQLCustomScalarTypeSpecIT {
6162
6263
@JsonCreator
6364
@JvmStatic
64-
fun create(rawValue: String) = UUID(converter.toScalar(rawValue))
65+
fun create(rawValue: Any) = UUID(converter.toScalar(rawValue))
6566
}
6667
}
6768

0 commit comments

Comments
 (0)