Skip to content

Don't serialize Option::None for Inputs #262

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

Closed
wants to merge 7 commits into from

Conversation

davidgraeff
Copy link
Contributor

@davidgraeff davidgraeff commented Aug 27, 2019

I have noticed that currently the library does not configure serde to skip Option::None and send json null values instead.

I'm not sure if it violates the graphql spec (https://graphql.github.io/graphql-spec/draft/#sec-Type-System.Non-Null.Nullable-vs-Optional), but not sending those fields is definitely allowed:

Fields are always optional within the context of a query, a field may be omitted and the query is still valid. [...] Inputs (such as field arguments), are always optional by default.

My graphql server however is absolutely not happy about null values for optional fields.
This PR adds the serde attribute to not serialize Option::None.

Requires all my other PRs for the sake of avoiding branch chaos on my side. If the last commit is fine, I'll be happy to extract and rebase it on master.

David Graeff added 7 commits August 27, 2019 08:27
* Specify most dependencies with major.minor version, no patch
* New syn versions syn::Visibility doesn't dervive from debug anymore.
* Use the Derivative crate to skip the "module_visibility" field for debug out.

Signed-off-by: David Graeff <david.graeff@web.de>
structopt uses the first letter for a "short" option.
"selected_operation" (with "o") as well as "output_directory" (with "out")
claimed "-o" which resulted in:

  thread 'main' panicked at 'Argument short must be unique
	-o is already in use

Fixed by removing the short option for "selected_operation" and
keep "-o" for output directory.

Signed-off-by: David Graeff <david.graeff@web.de>
If a camel case query name like "ping_query" is used,
the generated code fails. Fixed by using `to_camel_case`
for the struct name, while the module name still uses `to_snake_case`.

Even for a single word query name like "ping" that should work.

Signed-off-by: David Graeff <david.graeff@web.de>
…ak code generation

Add integration test (keywords_query.graphql+keywords_schema.graphql)

Signed-off-by: David Graeff <david.graeff@web.de>
The constructor method provides a simpler way to initialize a type with
many or only optional fields. Assuming an input type like this:

input CustomerInput {
  company: String
  customFields: [CustomFieldInput!]
  email: String
  firstName: String
  lastName: String
  phoneNumber: String
}

The generated code looks like so:

pub struct CustomerInput {
  pub company: Option<String>,
  ...
}
impl CustomerInput {
  pub fn new() -> Self {
    Self { company: None, custom_fields: None, ... }
  }
}

ALSO: More idomatic rust is generated by generating Option<Box<T>> instead of Box<Option<T>>.

Signed-off-by: David Graeff <david.graeff@web.de>

fixes
Signed-off-by: David Graeff <david.graeff@web.de>
@davidgraeff davidgraeff changed the title Skipnone Don't serialize Option::None for Inputs Aug 27, 2019
@tomhoule
Copy link
Member

Thanks for noticing that, it's indeed a problem! I have about 30 seconds to think about it now so I'll come back to this later, but I can think of cases where we would want the field to be omitted, and other cases where we would want it to be null. In graphql-ruby for example it's significant (server-side). Maybe Option<Option<Ty>>, where Some(None) is null, and just None would omit the field?

@theduke
Copy link
Member

theduke commented Aug 31, 2019

This is also a problem in Juniper.
A lot of GraphQL code out there uses the distinction of "absent" vs "null" vs "present" to represent different states.
EG a update resolver could interpret "absent" as ignored, "present but null" to mean: set to null, and "present" to set the value.

Serde can not interpret this out of the box. Eg Option<Option<i32>> is not supported (it would always be either None or Some(Some(10)).

We'd need a enum with a custom Serialize/Deserialize impl.

enum Optional<T> {
  None,
  Null,
  Some<T>,
}

If the client does get support for this I hope we can coordinate and use the same type.

@davidgraeff
Copy link
Contributor Author

An own enum type sounds like the correct solution. If "from" and "into" traits are implemented, it might not even break existing user code.

@mathstuf
Copy link
Contributor

Could you please rebase on master to handle conflicts? CI should also be working there.

@ronanyeah
Copy link

This would actually solve the problem I was trying to articulate here: #364

@keeslinp
Copy link

keeslinp commented Jul 4, 2021

I also have a similar issue since omitting a field and passing a null value are not the same. Is there a workaround in the meantime?

@tomhoule tomhoule closed this Jul 7, 2021
@tomhoule tomhoule deleted the branch graphql-rust:master July 7, 2021 07:10
@John0x
Copy link

John0x commented Jul 22, 2022

Why was this just closed without any comment? @tomhoule
This would have solved the issue that I'm having right now.

@mathstuf
Copy link
Contributor

It looks like it was targeting master and now the repo uses the main branch. Github closed it because it was targeting "nowhere". I don't know if you can update the target branch or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants