Khan / genqlient

a truly type-safe Go GraphQL client
MIT License
1.08k stars 111 forks source link

InputObject field defaults are ignored/overridden #228

Open kateile opened 2 years ago

kateile commented 2 years ago

Describe the bug Hi geeks, Thanks for this amazing lib. I have the following graphql input with default fields

input FormInput {
    hint: String
    inputType: MwappFormInputType = TEXT
    key: String = "form"
    label: String = "Fill form"
    maxLength: Int = 100
    multiSubmission: Boolean = false
    multiline: Boolean = false
    obscure: Boolean = false
}

input SendMessageInput {
    form: FormInput
}

type Mutation {
    sendMessage(connectionId: ID!, input: SendMessageInput!): String!
}

Which I use in golang like

mw.SendMessage(ConnectionId, mwapp.SendMessageInput{
        Message: "Hi, Please tell us your name. \n you can write it below",
        Form: &mwapp.FormInput{
            Key: FormKeyName.String(),
        },
    })

As you can see above I just use one field Key and ignore the rest. So I expect the default graphql fields specified in schema to be used when send request. But they are sent like null too.

To Reproduce Create mutation whose input have fields with default fields

Expected behavior Default fields to be respected when. I believe having pointer with omitempty in the generated code will be the solution. But I don't know how to archive this

genqlient version v0.5.0

Additional context My genqclient.yaml is

schema: schema.graphql
package: mwapp
operations:
- operations/*.graphql
generated: generated.go
use_struct_references : true
optional: pointer
bindings:
  Timestamp:
    type: time.Time

Any help on fixing this will be appreciated.

benjaminjkraft commented 2 years ago

Huh, I didn't realize input-object fields could have defaults! (For my future self: it's at InputObjectTypeDefinition which refers to InputValueDefinition.)

Does it work to use genqlient's omitempty option? For example you could add at the top of the file # @genqlient(for: "FormInput.inputType", omitempty: true), and so on for each field. (Obviously that's a bit verbose; we could talk about if there's a better way to do it, perhaps by extending #198 to allow an omitempty option.)

Fazt01 commented 7 months ago

Hi, yes the omitempty works -> the field is omitted in request and the server takes the default as value for that input field.

(tried with version github.com/Khan/genqlient v0.7.0)

One edge case, though, is when the field with default is non-null, e.g.

type Query {
  someQuery(input: Input!): String
}

input Input {
  inputField: Int! = 10
}

and I try to generate a request

# @genqlient(for: "Input.inputField", pointer: true, omitempty: true)
query MyQuery {
  $input: Input
} {
  someQuery(input: $input)
}

I get omitempty may only be used on optional arguments error, so in this case, I cannot specifically pick input fields that should respect the server default when empty.

I can, however, put omitempty to all fields by removing the for - without the above error

# @genqlient(pointer: true, omitempty: true)
query MyQuery {
  $input: Input
} {
  someQuery(input: $input)
}

which generates a structure as expected

type Input struct {
    InputField *int `json:"inputField,omitempty"`
}

IMO omitempty:false should be allowed to an input field that has a valid default (that is - it is nullable and it has not explicit default, or it has explicit default). A bit related to https://github.com/Khan/genqlient/issues/290 (false positive error on omitempty)