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

Null is not treated as a value. #1294

Closed
nathanielmoon opened this issue Mar 20, 2018 · 3 comments
Closed

Null is not treated as a value. #1294

nathanielmoon opened this issue Mar 20, 2018 · 3 comments

Comments

@nathanielmoon
Copy link

Hello, I have found what I believe to be an issue (v0.11.3). I'm currently writing a custom type and have found that I cannot interact with null values. The idea of this snippet is to convert incoming null values into -1 and to convert outgoing -1 values into null. Here is a quick snippet of a basic implementation:

new GraphQLScalarType({
    name: name,
    serialize : val => {
        if(val === -1){
            return null;
        } else {
            return val;
        }
    },
    parseValue: val => {
        if(val === null) {
            return -1;
        }

        if(Number.isInteger(val) && !isNaN(parseInt(val))){
            return parseInt(val);
        }

        throw "Integer Null Alias: Bad value being parsed";
    },
    parseLiteral : ast => {
        let val = ast.value;
        if(val === null) {
            return -1;
        }
        if(!isNaN(parseInt(val))){
            return parseInt(val);
        }
        throw "Integer Null Alias: Bad value in AST";
    }
});

What I find is that these methods are called when an integer is sent with the input type, but are not called when null is sent. Why is that? I've read a bunch of issues/articles relating to this issue, many of them indicating that it has been resolved, but it doesn't seem evident.

I've also seen indications that GraphQL uses null as an indicator that it should omit fields or auto fill them in.

Why would a framework that is meant to serve as an interface for databases such as SQL take a valid value such as null and apply side effects to the transmission of that value, extending its purpose beyond that of being a simple value?

Is what I'm trying to do an anti-pattern? If so, what other solutions are there? Is this not an issue? Suggestions?

Thank you! I'm a huge fan of the GraphQL effort, glad to see that its growing so fast.

@IvanGoncharov
Copy link
Member

What I find is that these methods are called when an integer is sent with the input type, but are not called when null is sent. Why is that?

@nightCapLounge It's expected behavior here is what spec says:

For all types below, with the exception of Non‐Null, if the explicit value null is provided, then the result of input coercion is null.

http://facebook.github.io/graphql/draft/#ScalarTypeDefinition

Here is direct analogy from JS, e.g. you have overridden String constructor and then you called JSON.parse('{ a: "foo", b: null }') you new constructor would be called to construct "foo" value but it would never be called for null.

and to convert outgoing -1 values into null

It's absolutely legal but be cautious if you wrap such scalar into Non-Null wrapper it will trigger a runtime error.

@nathanielmoon
Copy link
Author

nathanielmoon commented Mar 21, 2018

Thank you for the explanation, that tidbit from the spec explains the situation.

Though it seems to me that this is a flaw in the spec. Why would it treat the value null exceptionally from other values? This throws a real wrench in the works for any system that uses null as a standard value, (e.g. anything that uses SQL). That wrench is particularly big for someone like myself who wants to implement a translation routine through the custom type system, as I would with any other value. Is there a legitimate reason that I'm missing?

@leebyron Insights?

@leebyron
Copy link
Contributor

@IvanGoncharov is correct here. It's quite intentional that null is handled separately because null values have a specific semantic meaning in GraphQL.

I believe the solution to your scenario is just to not rely on custom scalars serialization. In your example I would expect a return type of Int, but because you're overriding the serialization behavior you would need to define a custom scalar. Instead, I suggest using the resolver function to do this late-stage coercion of null or missing values.

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

No branches or pull requests

3 participants