-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Support nullable & optional/required #542
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I would encourage creating a separate mutation root field for this case. Alternatively, use a boolean field to say whether the property is being deleted. In general, each mutation should do exactly one kind of write: updates and deletes are usually different enough that they warrant their own top-level codepath, even if they end up calling into the same server code. Back to your example, I'm also curious what the correct API call should be for "this property has never existed, and I still want it to not exist"? If you can pass in both a null value and a non-null value, how do you describe that situation? I'd argue this is exactly where an unset value makes sense (as much as the above API makes sense). All that being said: if this is valuable to you, I'd encourage expanding your proposal to be a Strawman, with some actual examples on how things ought to work, what the language change might look like, and why a "best-effort" way of doing things in the current spec won't work. |
in REST we just not send the field We need this to implement a patch or partial update. |
Might be useful to reference here as we are needing the same functionality - creating specific keys to delete values would make our API very complex and would make it more complex for any developer working with it: https://stackoverflow.com/questions/53194116/optional-but-non-nullable-fields-in-graphql |
I ran into a very similar problem of argument absence vs. Example use case:
scalar LocalDate
type Mutation {
updateContact(
id: ID!,
firstName: String,
lastName: String,
birthday: LocalDate,
children: Int,
…
): Contact
}
mutation {
updateContact(id: "123", firstName: "John", birthday: "1986-02-05", children: 2) { … }
} In (valid) GraphQL that approach only works if However, if
In my two GraphQL projects, I ran into that issue in plenty occasions. Now there are a few alternative approaches with current GraphQL. Every field is updated with every mutation
Create wrapper input types for every possible typeinput IntChange {
newValue: Int
}
input LocalDateChange {
newValue: LocalDate
}
A field that denotes whether to unset a specific data point
A field that denotes whether to update a specific data point
Add a special empty/unset value for each type
Split each one-per-entity mutation into one-per-entity-and-data-point mutation
Other approaches are not possible with current GraphQL without breaking the specification. Use a special default value to denote absencetype Mutation {
updateContact(
id: ID!,
firstName: String = ignore,
lastName: String = ignore,
birthday: LocalDate = ignore,
children: Int = ignore,
…
): Contact
}
Server treats explicit
|
@fluidsonic fwiw not completely following b/c, at least using apollo / typescript / graphql-code-generator, in your birthday example, i.e. for an input type like: input ContactInput {
firstName: String
birthday: LocalDate
} The generated TS types look at: interface ContactInput {
firstName?: string | undefined | null;
birthday?: string | undefined | null;
} Which matches that valid (ignoring the TS types) incoming-JSON-from-the-wire can be any three of:
So, AFAIU GraphQL's types already support the tri-state of set/unset/noop that you're looking for? Am I missing something? That said, I found this issue b/c I would like to be able to represent "this field is optional, but it cannot be null", i.e. a typescript type that looks like: interface ContactInput {
firstName?: string;
} And get rid of the However given that currently syntax wise:
And I generally assume these would have to remain that way for backwards compatibility, it's hard to think of a nice syntax that supports the/my desired
So it's modifying the value with Maybe that's not too bad actually... |
@stephenh looking at the spec I also have your problem though with non-nullable optional types. Same issue here - there's no "unspecified". Also, JSON is just one possible transport format for variables. It should also work in plain GraphQL notation - i.e. without variables. |
@fluidsonic "birthday should default to null if unspecified." ... huh, here I express my naivety in that I have not read the spec, but had just observed the behavior of apollo-server, where when a field is not present, it left as I.e. I just confirmed with this test mutation: mutation {
saveAuthor(input:{}){
id
}
} Where As a lazy ask, can you link to the section of the spec that asserts it should be null? |
@stephenh you're right. I've just read the coercing algorithm again and I've indeed missed something. There's a difference in Therefor the issue is indeed only non-nullable optional types. |
Also fwiw I think this is a duplicate of #476 |
Server: "Hey, the ID input is required!" |
I agree this seems like a duplicate of #476 |
Closing as duplicate 👍 |
In GraphQL we can mark a field that it is nullable or not by "!". But how to also mark that a field is required or optional?
Required means that this parameter must be passed, even if it is null.
Basically null has the meaning of "this property existed before, and I want to nullify its value". If there's no value, or the value needs not change (for requests, for example), it just shouldn't be sent.
For example an user have a birth day set in his profile, if he wants to update the birth day he must pass a value, but it is not allowed to pass null.
So, in this case a birth day type is not nullable, but it is optional, or user send a valida value or just not send this parameter.
This is supported by OpenAPI https://swagger.io/docs/specification/data-models/data-types/
The text was updated successfully, but these errors were encountered: