graphql-go / graphql-go/graphql

NewInputObject vs NewObject - Using NewObject type as arg for mutation?

Open
#234 4 comments 12 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.