Support for default schema values
The GraphQL spec allows for arguments to have default values:
- https://graphql.org/learn/schema/#arguments
Kotlin allows specifying default values:
- https://kotlinlang.org/docs/reference/functions.html#default-arguments
This information is not available on reflection though due to the way Kotlin compiles to the JVM:
- https://discuss.kotlinlang.org/t/kotlin-reflection-and-default-values/2254
- https://discuss.kotlinlang.org/t/retrieve-default-parameter-value-via-reflection/7314
We could solve this issue by adding a new annotation @GraphQLDefaultValue. This would require developers to duplicate some information but I think it would be worth it until we have a better way of extracting the info
fun getWidget(id: Int, @GraphQLDefaultValue(WidgetType.UNICORN) type: WidgetType = WidgetType.UNICORN) {
return database.getWidgetByIdAndType(id, type)
}
I like the annotation solution. This way we can add a check to the schema validation that all arguments with default values have the annotation.
A small issue: the values of annotations can only be a select list of values, basically primitives: https://kotlinlang.org/docs/reference/annotations.html#constructors
I thought this might work:
annotation class GraphQLDefaultValue(val kClass: KClass<*>, val valueAsString: String)
Then we could use it like kClass.parse(valueAsString) but there is not a generic method to parse a value from a string as far as I can see. We could add a custom extension function but I am not sure if this would work for all use cases.
Another approach is to have an annotation for each value @GraphQLDefaultString @GraphQLDefaultInt. But that means having to use and check lots of different values.
Any other ideas?
I realised my comment yesterday was invalid - we can't do the validation check for default values for the same reason we need this update...
I tried out a few options today but haven't come up with a good solution yet.
Here is an example on how default values can be achieved via custom directives, see:
https://github.com/ExpediaDotCom/graphql-kotlin/blob/861443970ae9859710967ae65c257e23bee47595/example/src/main/kotlin/com.expedia.graphql.sample/query/CustomDirectiveQuery.kt#L12
https://github.com/ExpediaDotCom/graphql-kotlin/blob/master/example/src/main/kotlin/com.expedia.graphql.sample/directives/StringEvalDirectiveWiring.kt
This supports defaults as strings with an enum type as example, but I don't think this entirely solves the problem https://github.com/amandaducrou/graphql-kotlin/pull/1
@amandaducrou That works, but seems unflexible, we'd need many different getValueAsXXXX. Wouldn't we also need to deal with coercing to support non-primitive default values?
What speaks against providing this via custom directives? Seems more flexible to me. Maybe some overhead for devs as the directives have to be created first... ... maybe we could build somekind of plugin system for custom directives and then we offer a few default custom directives, e.g. for string default values. hmmm
I agree it isn't the solution @d4rken - I had the code hanging around and wanted to commit it. I will look at the custom directives.
I'm wondering if this issue is taken care by anyone? I would like to contribute to this repo.
@keerthi4308 Feel free to propose a solution or provide a PR! This is not being worked on by someone today so you can assign yourself if you would like.
As you can see from the previous discussion there is a bit of complexity on the best way to solve it
We have added support for handling the default values set by Kotlin code in the functions here https://github.com/ExpediaGroup/graphql-kotlin/pull/981
However this information still does not get reflected to the generated schema. That means clients will not see if there is a default value for an argument. So today the work-around would be to just add more details in the GraphQLDescription.
This issue was re-opened because we are still not technically matching the GraphQL spec, but since server-side default values shouldn't really be concerns of the clients using GraphQL, this is no longer a higher priority. If someone has a good suggestion of how we can handle this with reflection feel free to comment or start a discussion.