graphql-kotlin icon indicating copy to clipboard operation
graphql-kotlin copied to clipboard

Support for default schema values

Open smyrick opened this issue 7 years ago • 10 comments

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)
}

smyrick avatar Oct 29 '18 17:10 smyrick

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.

amandaducrou avatar Oct 31 '18 06:10 amandaducrou

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?

smyrick avatar Oct 31 '18 18:10 smyrick

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.

amandaducrou avatar Nov 01 '18 06:11 amandaducrou

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

d4rken avatar Nov 20 '18 16:11 d4rken

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 avatar Dec 14 '18 00:12 amandaducrou

@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

d4rken avatar Dec 14 '18 08:12 d4rken

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.

amandaducrou avatar Dec 17 '18 01:12 amandaducrou

I'm wondering if this issue is taken care by anyone? I would like to contribute to this repo.

Keerthi4308 avatar Oct 17 '19 22:10 Keerthi4308

@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

smyrick avatar Oct 17 '19 23:10 smyrick

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.

smyrick avatar Dec 31 '20 09:12 smyrick