-
Notifications
You must be signed in to change notification settings - Fork 491
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
Support for Null Values in mutations #210
Comments
I am interested this as well. It would be nice to support or maybe use a struct tag to skip the runtime type checks against the schema? I'll poke around and maybe work on a PR. @neelance or @tonyghita any thoughts on this? |
@derekpitt we had a pretty severe bug in our system, so I ended up forking and providing a pretty crude solution that enables you to add another argument to your resolver functions, that can tell you if a field was provided or not. |
I'm also interested in this. An example would be an update mutation that updates only fields passed in the query (and some of them could be null). There seems to be no way to identify if particular argument was passed as null or simply omitted. Could you please suggest any workarounds? |
I second a solution on this. I have tried 2 different graphql projects written on go now and they both do not support null vs attribute not there. It would be really nice since this library has a pretty nice interface. |
This issue is not something that I am actively looking at. Indeed it is mentioned in the spec that |
#430 resolved this |
Following off of #430 if I wanted to handle the null vs omitted case for an array, e.g. type NullSliceString struct {
Value *[]string
Set bool
}
func (NullSliceString) ImplementsGraphQLType(name string) bool {
return name == "[String!]"
}
func (s *NullSliceString) UnmarshalGraphQL(input any) error {
s.Set = true
if input == nil {
return nil
}
switch v := input.(type) {
case []any:
val := make([]string, len(v))
for i := range v {
val[i] = v[i].(string)
}
s.Value = &val
return nil
default:
return fmt.Errorf("wrong type for [String!]: %T", v)
}
}
func (s *NullSliceString) Nullable() {} |
Hi @Slessi, package main
import (
"fmt"
"log"
"net/http"
"strings"
graphql "github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
)
type query struct{}
func (query) Test(args struct{ Vals *[]string }) string {
if args.Vals == nil {
return "Got <nil> input"
}
res := fmt.Sprintf("Got a non-nil array: [%v]", strings.Join(*args.Vals, ", "))
return res
}
func main() {
s := `
type Query {
test(vals: [String!]): String!
}
`
schema := graphql.MustParseSchema(s, &query{})
http.Handle("/query", &relay.Handler{Schema: schema})
log.Fatal(http.ListenAndServe(":8080", nil))
} Then after running ➜ curl -XPOST -d '{"query": "{ test1:test(vals: null) test2:test(vals: [\"val1\",\"val2\"]) }"}' localhost:8080/query | jq
{
"data": {
"test1": "Got <nil> input",
"test2": "Got a non-nil array: [val1, val2]"
}
} |
@pavelnikolov That doesn't address the key information I'm looking for though, namely 3 states, not 2 states:
with |
Ah, I'm sorry, you are right! In that case you need to implement the type NullUnmarshaller interface {
Unmarshaler
Nullable()
} Therefore your example above works fine: package main
import (
"fmt"
"log"
"net/http"
"strings"
graphql "github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
)
type query struct{}
func (query) Test(args struct{ Val NullSliceString }) string {
if !args.Val.Set {
return "Val is not set"
}
if args.Val.Value == nil {
return "Got <nil> input"
}
res := fmt.Sprintf("Got a non-nil array: [%v]", strings.Join(*args.Val.Value, ", "))
return res
}
type NullSliceString struct {
Value *[]string
Set bool
}
func (NullSliceString) ImplementsGraphQLType(name string) bool {
return name == "[String!]"
}
func (s *NullSliceString) UnmarshalGraphQL(input any) error {
s.Set = true
if input == nil {
return nil
}
switch v := input.(type) {
case []any:
val := make([]string, len(v))
for i := range v {
val[i] = v[i].(string)
}
s.Value = &val
return nil
default:
return fmt.Errorf("wrong type for [String!]: %T", v)
}
}
func (s *NullSliceString) Nullable() {}
func main() {
s := `
type Query {
test(val: [String!]): String!
}
`
schema := graphql.MustParseSchema(s, &query{})
http.Handle("/query", &relay.Handler{Schema: schema})
log.Fatal(http.ListenAndServe(":8080", nil))
} Then when I invoke that I got: ➜ curl -XPOST -d '{"query": "{ test1:test(val: null) test2:test(val: [\"val1\",\"val2\"]) test3:test }"}' localhost:8080/query | jq
{
"data": {
"test1": "Got <nil> input",
"test2": "Got a non-nil array: [val1, val2]",
"test3": "Val is not set"
}
} I'm not aware of a shorter way to implement this behavior. |
Ok cool, I'm new to go and wanted to make sure I'm on the right track - thanks a lot! |
According to the GraphQL spec, there should be a distinction between explicitly set
null
values and just plain omitted values (spec here: http://facebook.github.io/graphql/draft/#sec-Null-Value).It can be used to distinguish between ignoring a field and deleting the field value in a mutation fx.
Is there support for this already and I'm just missing it?
The text was updated successfully, but these errors were encountered: