hasura / go-graphql-client

Package graphql provides a GraphQL client implementation.
MIT License
395 stars 91 forks source link

ExecRaw vs Mutate/MutateRaw #97

Closed chuongle closed 1 year ago

chuongle commented 1 year ago

Hi,

I am having trouble understanding why for my case, I can only use ExecRaw instead of Mutate/MutateRaw. Hopefully someone can help me understand this.

I have a mutation like this on my server (not Hasura):

report(inputs: [JSON]!): [String!]!

On the client side, I have something like this:

var inputs = []health.DeviceInfo{} //imagine i already had some data in here

type NetworkInfo struct {
    Latency   string `json:"latency"`
    IPAddress string `json:"ipAddress"`
}

type DeviceInfo struct {
    Network  NetworkInfo `json:"network"`
    RecordId string      `json:"recordId"`
}

Solution 1: Using Mutate/MutateRaw

var mutation struct {
        Result []string `graphql:"report(inputs: $input)"`
}

var variables := map[string]interface{}{
        "inputs":  inputs,
}

err := client.Mutate(context.Background(), &mutation, variables)

This solution did not work for me. The server will throw an error Unknown type DeviceType. If I attempted to marshal that input and convert to json string then the server will throw error Expect [JSONObject] not [String] But if I implemented as Solution 2:

var mutation = `mutation ($input: [JSON]!) {result: report(inputs: $input)}`
result, err := client.ExecRaw(context.Background(), mutation, variables)

This solution works for me. The server did not throw any error and response properly.

I think it has something to do with using the struct vs string for the mutation but i'm not sure. If someone knows why, please help my understand more. I am still very new to Go. Thank you!

hgiasac commented 1 year ago

Hi,

Can you share a sample response? IMO the response type isn't a String array but is a JSON array. The Mutation method automatically infers the internal JSON response to parse the response.

ExecRaw doesn't parse the response so the error doesn't happen

chuongle commented 1 year ago

Hi @hgiasac

If you are asking about the response for the mutation, it's will return an array of String or ID to be exact.

["d76f196e-d21f-48b6-9d1c-7c8eab5b7670", "c2f54903-a71d-41d1-b6c7-d0f06359273e"]

However, the error is throwing at my nodejs server: Unknown type DeviceType. DeviceType is a struct on my client. The only different I can see so far is ExecRaw will take the query as a string while Mutate/MutateEaw will take the query as a pointer of the struct which maybe there is some infer at the request?

hgiasac commented 1 year ago

The GraphQL client constructs the input type from variables

type DeviceInfo struct {
    Network  NetworkInfo `json:"network"`
    RecordId string      `json:"recordId"`
}

var inputs = []health.DeviceInfo{}

var mutation struct {
        Result []string `graphql:"report(inputs: $input)"`
}

variables := map[string]any{
  "inputs":  inputs
}

// output 
// mutation ($inputs: [DeviceInfo!]!) {
//    report(inputs: $input) 
// }

So you need to ensure the input type is [DeviceInfo!]!. If the type name is JSON, you need to change the struct name or use the type alias

type JSON = health.DeviceInfo

var inputs = []JSON{}

You can use the ConstructMutation function to build the GraphQL string for debugging.

chuongle commented 1 year ago

@hgiasac Thank you for the advice! If I rename DeviceInfo to JSON I got it working. It looks like using type alias won't work because JSON is still DeviceInfo under the hood. I will look into ConstructMutation to debug some more. Will close issue for now