graphqlgraphql-go

GraphQL - Use Object as argument


I am building an API using GraphQL and one of the options of the API is to place an order

I am using Go 1.16 with graphql-go as the GraphQL backend

The JSON format for the PlaceOrder API call is:

{
   "order_reference":"unique order reference",
   "customer_order_reference":"customer order reference",
   "email_address":"email@example.com",
   "phone_number":"0123456789",
   "billing_address":{
      "name":"Billing name",
      "address_line_one":"Billing line one",
      "address_line_two":"Billing line two",
      "address_line_three":"Billing line three",
      "address_line_four":"Billing line four",
      "postcode":"billing postcode"
   },
   "delivery_address":{
      "name":"Delivery name",
      "address_line_one":"Delivery line one",
      "address_line_two":"Delivery line two",
      "address_line_three":"Delivery line three",
      "address_line_four":"Delivery line four",
      "postcode":"Delivery postcode"
   },
   "order_lines":[
      {
         "product_code":"123456",
         "quantity":1
      },
      {
         "product_code":"654321",
         "quantity":2
      }
   ]
}

In the Go code I have the Schema fields setup as:

graphql.Fields{
        "placeOrder": &graphql.Field{
            Type: order.PlaceOrder(),
            Args: graphql.FieldConfigArgument{
                "order_reference": &graphql.ArgumentConfig{
                    Type: graphql.String,
                },
                "customer_order_reference": &graphql.ArgumentConfig{
                    Type: graphql.String,
                },
                "email_address": &graphql.ArgumentConfig{
                    Type: graphql.String,
                },
                "phone_number": &graphql.ArgumentConfig{
                    Type: graphql.String,
                },
                "billing_address": &graphql.ArgumentConfig{
                    Type: graphql.NewObject(
                        graphql.ObjectConfig{
                            Name: "BillingAddress",
                            Fields: graphql.Fields{
                                "name": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "address_line_one": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "address_line_two": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "address_line_three": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "address_line_four": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "postcode": &graphql.Field{
                                    Type: graphql.String,
                                },
                            },
                        },
                    ),
                },
                "delivery_address": &graphql.ArgumentConfig{
                    Type: graphql.NewObject(
                        graphql.ObjectConfig{
                            Name: "DeliveryAddress",
                            Fields: graphql.Fields{
                                "name": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "address_line_one": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "address_line_two": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "address_line_three": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "address_line_four": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "postcode": &graphql.Field{
                                    Type: graphql.String,
                                },
                            },
                        },
                    ),
                },
                "order_lines": &graphql.ArgumentConfig{
                    Type: graphql.NewList(graphql.NewObject(
                        graphql.ObjectConfig{
                            Name: "Line",
                            Fields: graphql.Fields{
                                "part_number": &graphql.Field{
                                    Type: graphql.String,
                                },
                                "quantity": &graphql.Field{
                                    Type: graphql.String,
                                },
                            },
                        },
                    )),
                },
            },
            Resolve: func(p graphql.ResolveParams) (interface{}, error) {
                // Code to interact with Database and assign value to status, reference depending on result of database INSERT and return as "response"
                return response, nil
            },
        },
    }

I have tried a few different ways of passing data to the addresses and order lines but don't seem to be able to get them passed through successfully: For example I tried the below and the map[] is the result of fmt.Printf("%+v\n", p.Args)

query:

{
    placeOrder(
        order_reference:"order reference"
        customer_order_reference: "cust order reference"
        billing_address: {
           name: "Billing Name"
           address_line_one: "Address line one"
           address_line_two: "Address line one"
           address_line_three: "Address line one"
           address_line_four: "Address line one"
           postcode: "Post code"
        }
        delivery_address: {
           name: "Delivery Name"
           address_line_one: "Address line one"
           address_line_two: "Address line one"
           address_line_three: "Address line one"
           address_line_four: "Address line one"
           postcode: "Post code"
        }
        order_lines: [
            {
                part_number: "123456"
                quantity: 1
            }
        ]
        ){
            status,
            reference
        }
}

result:

map[
customer_order_reference:cust order reference
order_lines:[<nil>]
order_reference:order reference
]

Solution

  • Answer provided by @xadm

    Solution highlighted in https://stackoverflow.com/a/41230015/6124657

    var InputType = graphql.NewInputObject(
        graphql.InputObjectConfig{
            Name: "InputTypeName",
            Fields: graphql.InputObjectConfigFieldMap{
                "sub_field_one": &graphql.InputObjectFieldConfig{
                    Type: graphql.String,
                },
                "sub_field_two": &graphql.InputObjectFieldConfig{
                    Type: graphql.String,
                },
            },
        },
    )
    

    In the Args section replace the original NewObject(...) with NewInputObject(...)

    "billing_address": &graphql.ArgumentConfig{
                    Type: graphql.NewInputObject(
                        graphql.InputObjectConfig{
                            Name: "BillingAddress",
                            Fields: graphql.InputObjectConfigFieldMap{
                                "address_line_one": &graphql.InputObjectFieldConfig{
                                    Type: graphql.String,
                                },
                                "address_line_two": &graphql.InputObjectFieldConfig{
                                    Type: graphql.String,
                                },
                               ...
                            },
                        },
                    ),
                },
    

    This generates a map with the sub fields