Skip to content

Non-nullable OptionalInput #1216

@paulschuetz

Description

@paulschuetz

Assume we have an input class for a update mutation on some kind of dog 🐕 enitity, which looks like this.

data class DogUpdateInput(
    val id: String,
    val name: OptionalInput<String>,
    val description: OptionalInput<String>
)

We always need the id of the dog in the input to find the corresponding entity. Both name and description are optional and can be set to either some String or null. But now I have the requirement that it SHOULD NOT be possible that name ist set to null. So I want an input to be optional in the request (maybe I just want to update the description but not the name) but this does not mean that it always allowed to be a null value (like name should not be allowed to be set to null).
I would expect this to be configuratble by setting the desired generics of OptionalInput, like so:

data class DogUpdateInput(
    val id: String,
    val name: OptionalInput<String>,
    val description: OptionalInput<String?>
)

Note that withval description: OptionalInput<String?>, description can be set to null but with val name: OptionalInput<String>, name should not be able to be set to null and I want a validation error message if someone tries to do so in a request. But this is not possible with the current OptionalInput implementation, because the value field of OptionalInput is always nullable!

I looked into the OptionalInput source code and found the current implementation which looks like so:

/**
* Wrapper holding explicitly specified value including NULL.
*/
class Defined<out U> @JsonCreator constructor(@JsonValue val value: U?) : OptionalInput<U>() {
    override fun toString(): String = "Defined(value=$value)"
}

As you can see the constructor parameter value of the Defined class is of type U?. I think this is a design issue which leads to my described issue. The generic parameter U should be responsible for deciding whether the value is nullable or not. Therefore I suggest that the constructor should look like so:

/**
* Wrapper holding explicitly specified value including NULL.
*/
class Defined<out U> @JsonCreator constructor(@JsonValue val value: U) : OptionalInput<U>() {
    override fun toString(): String = "Defined(value=$value)"
}

Note that value is now of type U and the consumer is responsible for deciding whether an OptionalInput can be set to null or must have a value.

I would love to hear what you think! 😄

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions