graphql-go / graphql-go/graphql
NewInputObject vs NewObject - Using NewObject type as arg for mutation?
- Dominant language
- Go
- Stars
- 10.1k
- Forks
- 845
- PR merge metrics
- No merged PRs in 30d
Description
I'm writing a schema, and have found I needed to create both NewObject and NewInputObjects.
If I want to use a type as an arg to a mutation/query then it must be an NewInputObject.
But if I want to return the type in response to a query, then it needs to be a NewObject type.
While the solution works, it seems like alot of duplication. Am I missing something here?
See code below.
Here I have a model for my data:
```
type Author struct {
Name string `json:"name"`
Age int `json:"age"`
Books []Book `json:"books"`
}
type Book struct {
Title string `json:"title"`
Editions []string `json:"editions"`
}
```
I have described these types as graphql objects
```
bookType := graphql.NewObject(graphql.ObjectConfig{
Name: "Book",
Fields: graphql.Fields{
"title": &graphql.Field{Type: graphql.String},
"editions": &graphql.Field{Type: graphql.NewList(graphql.String)},
},
})
authorType := graphql.NewObject(graphql.ObjectConfig{
Name: "Author",
Fields: graphql.Fields{
"name": &graphql.Field{Type: graphql.String},
"age": &graphql.Field{Type: graphql.Int},
"books": &graphql.Field{Type: graphql.NewList(bookType)},
},
})
```
And now I have a mutation to create authors:
N.B I have 3 args
name : string
age : int
books : list of bookType
```
var rootMutation = graphql.NewObject(graphql.ObjectConfig{
Name: "RootMutation",
Fields: graphql.Fields{
"createAuthor": &graphql.Field{
Type: authorType, // the return type for this field
Description: "Execute a new command - this creates a new command record",
Args: graphql.FieldConfigArgument{
"name": &graphql.ArgumentConfig{
Type: graphql.String,
},
"age": &graphql.ArgumentConfig{
Type: graphql.Int,
},
"books": &graphql.ArgumentConfig{
Type: graphql.NewList(bookType),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
log.Printf("Args: %v", params.Args)
jsonString, err := json.Marshal(params.Args)
if err != nil {
fmt.Println("Error encoding JSON")
return nil, nil
}
author := Author{}
json.Unmarshal([]byte(jsonString), &author)
return author, nil
},
},
},
})
```
If I make a request with the following curl I get an error:
N.B books is passed in as a variable using json.
```
curl -XPOST http://localhost:8080/graphql -H 'Content-Type: application/json' -d \
'{
"query": "mutation CreateAuthor($name:String,$age:Int,$books:[Book]){createAuthor(name:$name,age:$age,books:$books){name age books {title}}}",
"variables": "{\"name\": \"Dave J\", \"age\": \"99\", \"books\": [ { \"title\" : \"My First Book\", \"editions\" : [ \"one\", \"two\"] }, {\"title\" : \"My Second Book\", \"editions\" : [ \"one\", \"two\"]}] }"
}'
```
```
message": "Variable \"$books\" cannot be non-input type \"[Book]\"."
```
So after some googling I changed the NewObject to be NewInputObject
```
bookType := graphql.NewInputObject(graphql.InputObjectConfig{
Name: "BookType",
Fields: graphql.InputObjectConfigFieldMap{
"title": &graphql.InputObjectFieldConfig{Type: graphql.String},
"editions": &graphql.InputObjectFieldConfig{Type: graphql.NewList(graphql.String)},
},
})
```
The mutation now succeeds and returns this data:
N.B the author details have been returned, but the nestled type books is null
```
{
"data": {
"createAuthor": {
"age": 99,
"books": [
null,
null
],
"name": "Doyle"
}
},
```
So I now create two types. A bookType (NewObject) and a bookInputType (NewInputObject). In my mutation the arg is changed bookInputType and in the curl request the type is also changed to BookInput.
```
bookInputType := graphql.NewInputObject(graphql.InputObjectConfig{
Name: "BookInput",
Fields: graphql.InputObjectConfigFieldMap{
"title": &graphql.InputObjectFieldConfig{Type: graphql.String},
"editions": &graphql.InputObjectFieldConfig{Type: graphql.NewList(graphql.String)},
},
})
bookType := graphql.NewObject(graphql.ObjectConfig{
Name: "Book",
Fields: graphql.Fields{
"title": &graphql.Field{Type: graphql.String},
"editions": &graphql.Field{Type: graphql.NewList(graphql.String)},
},
})
```
Now when I make a request, everything works. Is this expected, or is there a better way to implement this?
Contributor guide
Assessment
This issue has not been assessed yet.