When an input object field is set inline from a variable (e.g. { truthyBoolean: $truthyBoolean }) and that variable is left undefined, the schema's default value for the field isn't applied. Instead, the resolver receives nil. If the entire input object is passed as a variable, or if the field is omitted altogether, the default is applied as expected. This behavior is inconsistent.
Schema:
input DefaultInput {
falsyBoolean: Boolean = false
truthyBoolean: Boolean = true
}
type Mutation {
defaultInput(input: DefaultInput!): DefaultParametersMirror!
}
Operation (no variables provided, so $truthyBoolean is undefined):
mutation ($truthyBoolean: Boolean) {
defaultInput(input: { truthyBoolean: $truthyBoolean }) {
falsyBoolean
truthyBoolean
}
}
Expected:
The underlying issue appears to be in gqlparser. The parser materializes the inline object { truthyBoolean: $truthyBoolean } as {"truthyBoolean": nil} which means the key is present with a nil value. gqlgen's generated method unmarshalInputDefaultInput only fills a default value when the key is absent but skips it if it's present but is nil.
Reproduction:
It can be added as a subtest to codegen/testserver/singlefile/defaults_test.go in the test method TestDefaults
t.Run("default input field from undefined variable", func(t *testing.T) {
resolvers.MutationResolver.DefaultInput = func(
ctx context.Context,
input DefaultInput,
) (*DefaultParametersMirror, error) {
return &DefaultParametersMirror{
FalsyBoolean: input.FalsyBoolean,
TruthyBoolean: input.TruthyBoolean,
}, nil
}
var resp struct{ DefaultInput *DefaultParametersMirror }
// No variables are provided, so $truthyBoolean is undefined.
err := c.Post(`mutation ($truthyBoolean: Boolean) {
defaultInput(input: { truthyBoolean: $truthyBoolean }) {
falsyBoolean
truthyBoolean
}
}`, &resp)
require.NoError(t, err)
assertDefaults(t, resp.DefaultInput) // fails: truthyBoolean is nil, wants true
})
Related gqlparser issue: vektah/gqlparser#347
However, because it appears directly in gqlgen, I'm opening this issue here for visibility and tracking. I’d be happy to work on a fix for this.
When an input object field is set inline from a variable (e.g.
{ truthyBoolean: $truthyBoolean }) and that variable is left undefined, the schema's default value for the field isn't applied. Instead, the resolver receives nil. If the entire input object is passed as a variable, or if the field is omitted altogether, the default is applied as expected. This behavior is inconsistent.Schema:
Operation (no variables provided, so $truthyBoolean is undefined):
Expected:
truthyBoolean = true
falsyBoolean = false
Actual:
falsyBoolean = false (default applied since it's absent from the object)
truthyBoolean = null (the resolver receives nil and the default is ignored)
The underlying issue appears to be in gqlparser. The parser materializes the inline object
{ truthyBoolean: $truthyBoolean }as{"truthyBoolean": nil}which means the key is present with a nil value. gqlgen's generated method unmarshalInputDefaultInput only fills a default value when the key is absent but skips it if it's present but is nil.Reproduction:
It can be added as a subtest to codegen/testserver/singlefile/defaults_test.go in the test method TestDefaults
Related gqlparser issue: vektah/gqlparser#347
However, because it appears directly in gqlgen, I'm opening this issue here for visibility and tracking. I’d be happy to work on a fix for this.