graphql-go / graphql-go/graphql
Returning nil interface{} vs. returning nil pointer in Resolve functions
- Dominant language
- Go
- Stars
- 10.1k
- Forks
- 845
- PR merge metrics
- No merged PRs in 30d
Description
I discovered that graphql-go behaves differently if I directly return nil from a `Resolve` function or if a return nil which is stored inside a pointer field.
In the first case graphql-go will directly interpret it is nil and won't call the child fields Resolve function. If I return a nil pointer it will instead call the chields field resolve function and will set the `Source` argument to nil. This is at least in my cases not what I expect, as I expect that returning nil should mean sending nil as the fields value to the client and not trying to resolve fields for that.
Some code to show the difference:
``` go
type ChildStruct struct {
FieldA string
}
type MainStruct struct {
Child *ChildStruct
}
var ChildStructSchema = NewObject(graphql.ObjectConfig{
Name: "ChildStruct",
Fields: graphql.Fields{
"fieldA": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
switch v := p.Source.(type) {
case ChildStruct:
return p.FieldA
case *ChildStruct:
return p.FieldA
default:
panic("didn't expect that")
}
},
},
},
})
var MainStructSchema = NewObject(graphql.ObjectConfig{
Name: "MainStruct",
Fields: graphql.Fields{
"child": &graphql.Field{
Type: ChildStructSchema,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
v := p.Source.(MainStruct)
// If I apply this method then child we be transmitted as nil and the Resolve methods
// in ChildStructSchema won't be called
if v.Child == nil {
return nil, nil
}
return v.Child, nil
// If I however directly return the field (nil pointer) then the resolve method
// will be called with a nil Source
return v.Child
},
},
},
})
// I I apply the second MainStruct.child resolving method I can trigger a panic with having a MainStruct
// defined as
var main = MainStruct{
Child: nil,
}
```
I think the reason for that is that the executor probably only checks if the return value is directly nil but not whether a nil is encapsulated in an interface. To work around this graphql-go would need to check if there's some pointer in the return value and if this nil besides only directly checking for nil.
What I don't know was if this is behavior was an explicit design decision or if it's just a bug. I currently can't see any situation where a nil pointer should lead the resolution of child fields - because if the Source is really not needed and childs should generated through some other mechanism one could simply return a non-nil dummy value. And as the executor anyway seems to check the returned value via reflection it could also check if this is Pointer and treat a nil pointer as a null value. Of course only if NonNull is not specified - otherwise it should be an error.
Contributor guide
Assessment
This issue has not been assessed yet.