Skip to content
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

Should a variable value of undefined be converted to null? #2533

Closed
yaacovCR opened this issue May 8, 2020 · 17 comments
Closed

Should a variable value of undefined be converted to null? #2533

yaacovCR opened this issue May 8, 2020 · 17 comments

Comments

@yaacovCR
Copy link
Contributor

yaacovCR commented May 8, 2020

See ardatan/graphql-tools#1453

yaacovCR added a commit to ardatan/graphql-tools that referenced this issue May 8, 2020
@yaacovCR
Copy link
Contributor Author

yaacovCR commented May 8, 2020

Variables not present within the variableValues object are left alone (https://github.com/graphql/graphql-js/blob/master/src/execution/values.js#L103) but variables present but undefined are later coerced to null.

This may be by design?

yaacovCR added a commit to ardatan/graphql-tools that referenced this issue May 8, 2020
@IvanGoncharov
Copy link
Member

@yaacovCR Excellent question 👍
Technically it's correct according to the spec:

Let hasValue be true if variableValues provides a value for the name variableName.

http://spec.graphql.org/draft/#sel-JANLLFCFFJCAACIB1nF

But pragmatically in JS we can treat undefined as absent value.
However, we need a consistent approach to undefined in this library and since undefined returned from resolver is converted to null we need to maintain the same rule in all other places that work with values.
Does this fully answer your question?

@IvanGoncharov
Copy link
Member

@yaacovCR Thinking more about this maybe we need to change this in the next major version.
Do you know how widespread it is to set allowUndefinedInResolve to false in user codebases?
https://github.com/ardatan/graphql-tools/blob/2b1b5e3e48f23a81b286c48134507b6666eb0ccc/packages/schema/src/makeExecutableSchema.ts#L51

@yaacovCR
Copy link
Contributor Author

I'm not sure I understand the correspondence you're making between conversion of undefined to null within the return value of resolvers and the issue here...

I would think passing a value of undefined in the variable values should be equivalent to not passing it at all and returning undefined in a resolver should be equivalent to not returning anything which should also be coerced to null...

@yaacovCR
Copy link
Contributor Author

but in regards to your question, I am not personally sure, others might know better, actually forgot that option existed

@yaacovCR
Copy link
Contributor Author

To use typescript terms, maybe, I think undefined and void should be treated the same within graphql-js...

@IvanGoncharov IvanGoncharov added this to the 16.0.0-alpha.1 milestone May 21, 2020
@IvanGoncharov
Copy link
Member

@yaacovCR I think you right.
But it's too late in my timezone to think clearly so I need to sleep with it.

I'm not sure I understand the correspondence you're making between conversion of undefined to null within the return value of resolvers and the issue here...

Because of this line undefined as variable value is converted to null and the same transformation happens for return value of resolvers. It's way better to have a single rule that undefined => null for the entire library.

@yaacovCR
Copy link
Contributor Author

Lol, get some sleep, I am pretty sure as this is not caused an issue until now and there is an acceptable workaround in GraphQL tools already, that this is the least of all issues in terms of priority

@alfaproject
Copy link

This is a breaking change and we can't migrate to the latest version of graphql-tools easily.

In some of our resolvers we pass the arguments/input directly to MongoDB as the filter object. null has meaning in MongoDB (https://docs.mongodb.com/manual/tutorial/query-for-null-fields/) and some of our queries with advanced filters stopped working and quite a lot of unexpected results throughout our back-office that makes extensive use of filtering queries. ):

At the very least, there could be a breaking change note on v5. If a configuration option can be made for this, even better.

@yaacovCR
Copy link
Contributor Author

Should be fixed in v6 of graphql-tools, what version are you on?

@alfaproject
Copy link

I was updating to v5 because I'm using Apollo Server and wanted to get rid of the fork. I wasn't considering v6 because it installs too many packages that we don't use so I'd probably wait for the Apollo team to decide the way forward on that.

@yaacovCR
Copy link
Contributor Author

Actually, we could probably take the discussion offline as this is not really relevant to this issue...but in v6 you should be able to decrease bundle size over v5 by only including the packages you need, import from @graphql-tools/schema, @graphql-tools/wrap @graphql-tools/stitch for whatever functionality you need rather than from graphql-tools, although latter is supported for backwards compatibility.

This is actually one of the main improvements in v6!

If you are doing so already and bundle size has gone up, you should probably open an issue at https://github.com/ardatan/graphql-tools/issues, maybe more of the generic utility functions need to be moved elsewhere.

@IvanGoncharov IvanGoncharov removed this from the 16.0.0-alpha.1 milestone Aug 13, 2020
@yaacovCR
Copy link
Contributor Author

This could be considered for v17

@yaacovCR
Copy link
Contributor Author

yaacovCR commented Feb 6, 2023

Updating code site:

const variableName = valueNode.name.value;
if (
variableValues == null ||
!hasOwnProperty(variableValues, variableName)
) {
if (argDef.defaultValue !== undefined) {
coercedValues[name] = argDef.defaultValue;
} else if (isNonNullType(argType)) {
throw new GraphQLError(
`Argument "${name}" of required type "${inspect(argType)}" ` +
`was provided the variable "$${variableName}" which was not provided a runtime value.`,
{ nodes: valueNode },
);
}
continue;
}
isNull = variableValues[variableName] == null;

@IvanGoncharov et al --

Can this be considered for v17?

@yaacovCR
Copy link
Contributor Author

yaacovCR commented Feb 6, 2023

Actually, I think this case should not exist, and was due to improper use of getArgumentValues in client code within graphql-tools that has since been fixed. Perhaps the code could still be cleaned up, though.

@yaacovCR yaacovCR closed this as completed Feb 6, 2023
@yaacovCR
Copy link
Contributor Author

yaacovCR commented Feb 6, 2023

#3811 (comment)

@robross0606
Copy link

I am seeing this problem with v16.6.0. A scalar argument submitted on a mutation as undefined is converted to null by the time it reaches the resolver. This makes it impossible to delineate the difference between an intentionally submitted null and a completely left-out optional argument. Tracing this out, the value is correctly carried to the server as undefined until it reaches the getArgumentValues() call in execute.js. At this point the resulting args variable has swapped out undefined for null and the original input fidelity is lost by the time the resolver is invoked. Is this a regression?

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

No branches or pull requests

4 participants