Skip to content

Commit

Permalink
Return graphql.Null in interface resolver when passed a typed nil
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Nicolas Maquet committed Nov 13, 2019
1 parent 15b3058 commit 85ca9ef
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 0 deletions.
3 changes: 3 additions & 0 deletions codegen/interface.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ func (ec *executionContext) _{{$interface.Name}}(ctx context.Context, sel ast.Se
return ec._{{$implementor.Name}}(ctx, sel, &obj)
{{- end}}
case *{{$implementor.Type | ref}}:
if obj == nil {
return graphql.Null
}
return ec._{{$implementor.Name}}(ctx, sel, obj)
{{- end }}
default:
Expand Down
99 changes: 99 additions & 0 deletions codegen/testserver/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions codegen/testserver/interfaces.graphql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
extend type Query {
shapes: [Shape]
noShape: Shape @makeNil
noShapeTypedNil: Shape @makeTypedNil
}

interface Shape {
Expand All @@ -18,3 +19,4 @@ type Rectangle implements Shape {
union ShapeUnion @goModel(model:"testserver.ShapeUnion") = Circle | Rectangle

directive @makeNil on FIELD_DEFINITION
directive @makeTypedNil on FIELD_DEFINITION
24 changes: 24 additions & 0 deletions codegen/testserver/interfaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,28 @@ func TestInterfaces(t *testing.T) {
var resp interface{}
c.MustPost(`{ noShape { area } }`, &resp)
})

t.Run("interfaces can be typed nil", func(t *testing.T) {
resolvers := &Stub{}
resolvers.QueryResolver.NoShapeTypedNil = func(ctx context.Context) (shapes Shape, e error) {
panic("should not be called")
}

srv := handler.GraphQL(
NewExecutableSchema(Config{
Resolvers: resolvers,
Directives: DirectiveRoot{
MakeTypedNil: func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
var circle *Circle
return circle, nil
},
},
}),
)

c := client.New(srv)

var resp interface{}
c.MustPost(`{ noShapeTypedNil { area } }`, &resp)
})
}
3 changes: 3 additions & 0 deletions codegen/testserver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ func (r *queryResolver) Shapes(ctx context.Context) ([]Shape, error) {
func (r *queryResolver) NoShape(ctx context.Context) (Shape, error) {
panic("not implemented")
}
func (r *queryResolver) NoShapeTypedNil(ctx context.Context) (Shape, error) {
panic("not implemented")
}
func (r *queryResolver) Issue896a(ctx context.Context) ([]*CheckIssue896, error) {
panic("not implemented")
}
Expand Down
4 changes: 4 additions & 0 deletions codegen/testserver/stub.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 85ca9ef

Please sign in to comment.