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

Don't crash when interface resolver returns a typed nil #929

Merged
merged 4 commits into from
Nov 28, 2019

Conversation

nmaquet
Copy link
Contributor

@nmaquet nmaquet commented Nov 13, 2019

When implementing a resolver that returns an interface, it is convenient to be able to return a nil pointer of the underlying struct. This currently causes gqlgen's generated code to panic (nil pointer dereference).

Consider the schema:

interface Animal { name: String! }
type Dog implements Animal { name: String! age: Float }
type Query {
    animal: Animal
}

The following implementation leads to a crash:

func (r *queryResolver) Animal(ctx context.Context) (Animal, error) {
    var ptr *Dog
    return ptr, nil 
}

The fix is very simple, we have added an extra check in interface.gotpl, like so:

case *{{$implementor.Type | ref}}:
    if obj == nil {
        return graphql.Null
    }
    return ec._{{$implementor.Name}}(ctx, sel, obj)

I have:

  • Added tests covering the bug / feature (see testing)
  • Updated any relevant documentation (see docs)

Nicolas Maquet added 2 commits November 13, 2019 17:30
Go's dreaded _typed nil_ strikes again. Nil pointers of struct types
aren't equal to nil interface pointers.

See https://golang.org/doc/faq#nil_error
@coveralls
Copy link

coveralls commented Nov 13, 2019

Coverage Status

Coverage remained the same at 62.119% when pulling fcfe595 on nmaquet:check-nil-interface-ptrs into 15b3058 on 99designs:master.

@vvakame
Copy link
Collaborator

vvakame commented Nov 18, 2019

typed nil is not means nil.
so, tests are succeeded with below changes without your codegen/interface.gotpl patches.

diff --git a/codegen/testserver/interfaces.go b/codegen/testserver/interfaces.go
index 18488d8..1aa520b 100644
--- a/codegen/testserver/interfaces.go
+++ b/codegen/testserver/interfaces.go
@@ -17,6 +17,9 @@ type Circle struct {
 }

 func (c *Circle) Area() float64 {
+       if c == nil {
+               return 0
+       }
        return c.Radius * math.Pi * math.Pi
 }

If you wanna convert typed nil to nil, You can do it in resolver middleware.
Is it enough?

Nicolas Maquet added 2 commits November 19, 2019 11:53
This added test shows that the `_Dog_species` automatically generated
resolver will crash unless the extra nil check is added in
`interface.gotpl`.
@nmaquet
Copy link
Contributor Author

nmaquet commented Nov 18, 2019

@vvakame Thank you for looking into this.

so, tests are succeeded with below changes without your codegen/interface.gotpl patches.
Yes, you are correct, but there is still a problem I think. I have added another test that shows that, when using automatically generated field resolvers, returning a typed nil from an interface resolver will lead to a crash in gqlgen's generated code.

Look at this field resolver:
https://github.com/nmaquet/gqlgen/blob/check-nil-interface-ptrs/codegen/testserver/generated.go#L3517

This line will cause a panic when executing the query unless an extra check is done.

@vvakame
Copy link
Collaborator

vvakame commented Nov 19, 2019

🤔
I suggest you to implement nil checks in here.

gqlgen/codegen/field.gotpl

Lines 122 to 124 in 15b3058

{{- else if .IsVariable -}}
return {{.GoReceiverName}}.{{.GoFieldName}}, nil
{{- end }}

Do you think this is a good idea?

@vektah vektah merged commit 9e989d9 into 99designs:master Nov 28, 2019
cgxxv pushed a commit to cgxxv/gqlgen that referenced this pull request Mar 25, 2022
Don't crash when interface resolver returns a typed nil
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.

4 participants