Graphql: How to unmarshall lists in resolve function

Created on 8 Aug 2017  路  3Comments  路  Source: graphql-go/graphql

Hi,
I have a simple mutation. It takes a couple of arguments (2 strings and 1 List of strings). I'm having trouble correctly unmarshalling the string. Is there a recommended approach to this - I can't find any other examples.

Here is the mutation:

var rootMutation = graphql.NewObject(graphql.ObjectConfig{
        Name: "RootMutation",
        Fields: graphql.Fields{
            "WriteBook": &graphql.Field{
                Type:        bookType, // 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,
                    },
                    "author": &graphql.ArgumentConfig{
                        Type: graphql.String,
                    },
                    "editions": &graphql.ArgumentConfig{
                        Type: graphql.NewList(graphql.String),
                    },
                },
                Resolve: func(p graphql.ResolveParams) (interface{}, error) {

                    log.Printf("ARGS:", p.Args)

                    name, _ := p.Args["name"].(string)
                    log.Printf("Name: %s", name)

                    author, _ := p.Args["author"].(string)
                    log.Printf("Author: %s", author)

                    editions, _ := p.Args["editions"].([]string)
                    log.Printf("Editions: %s", editions)


                    book := Book{
                        Name:   name,
                        Author: author,
                    }
                    database[name] = book

                    return book, nil
                },
            },
        },
    })

If I make the following request:

curl -XPOST http://localhost:8080/graphql -H 'Content-Type: application/json' -d \
'{
  "query": "mutation CreateNewBook($name:String,$author:String,$editions:[String]){WriteBook(name:$name,author:$author,editions:$editions){name author}}",
  "variables": "{\"name\": \"War and Peace\", \"author\": \"Some Guy\", \"editions\": [\"First\", \"Second\"]}"
}'

I can see the following logged:

ARGS:%!(EXTRA map[string]interface {}=map[editions:[First Second] name:War and Peace author:Some Guy])
Name: War and Peace
Author: Some Guy
Editions: []

I've attempted to cast the editions to []string. That just returns an empty array. If I try to cast to a string that also fails.
Any suggestions on how this should be handled?

Most helpful comment

In the end, I had to cast to []interface{} then iterate over that appending to a string list. There maybe a more efficient mechanism, but this works.

editions, _ := p.Args["editions"].([]interface{})
aString := make([]string, len(editions))
for _, v := range editions {
    aString = append(aString, v.(string))
}

All 3 comments

In the end, I had to cast to []interface{} then iterate over that appending to a string list. There maybe a more efficient mechanism, but this works.

editions, _ := p.Args["editions"].([]interface{})
aString := make([]string, len(editions))
for _, v := range editions {
    aString = append(aString, v.(string))
}

Is there a better way to do it?

In the end, I had to cast to []interface{} then iterate over that appending to a string list. There maybe a more efficient mechanism, but this works.

editions, _ := p.Args["editions"].([]interface{})
aString := make([]string, len(editions))
for _, v := range editions {
    aString = append(aString, v.(string))
}

I think you are expanding your array with the append function after you initialized it with the correct length.
Let's pretend you you have the following "editions" ["A", "B", "C"]. With your code the string array aString will look like this ["", "", "", "A", "B", "C"].

I would suggest the following:

editions, _ := p.Args["editions"].([]interface{})
aString := make([]string, len(editions))
for i, v := range editions {
    aString[i] = v.(string) // use the index here
}

You can just assign the values to the positions in the array.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SDkie picture SDkie  路  6Comments

michelalbers picture michelalbers  路  3Comments

jiharal picture jiharal  路  5Comments

zbintliff picture zbintliff  路  3Comments

rubberviscous picture rubberviscous  路  4Comments