hasura / go-graphql-client

Package graphql provides a GraphQL client implementation.
MIT License
405 stars 94 forks source link

BUG: Mutation generates error #61

Closed droslean closed 1 year ago

droslean commented 1 year ago

My mutation

mutation{
  addImage(input: {name: "test", namespace: "test-ns", imageStreamRef: "test-ns/test:latest", releaseVersion: "master"}) {
    numUids
  }
}

Error:

error="Message: Expected {, found <EOF>, Locations: [{Line:1 Column:9}]"

The above mutation is correct and its working. The problem is with the client.

I am only trying to do

if err := client.Mutate(context.Background(), &mutation, nil); err !=nil{
    return err
}
droslean commented 1 year ago

@hgiasac cc

hgiasac commented 1 year ago

Hi @droslean Please share your Go struct sample code and the GraphQL schema if possible so we can reproduce the error

droslean commented 1 year ago

@hgiasac Can you let me know what the structs should look like? I tried everything.

hgiasac commented 1 year ago

@droslean just send the code that you request the mutation, for example:

var mutation struct {
  AddImage struct {
    NumUIDs int `graphql:"numUids"`
  } `graphql:"addImage(input: $input)"`
}

// you need to know the GraphQL type of the input
type Input map[string]interface{}

variables := map[string]interface{}{
  "input": Input{
    "name": "test", 
    "namespace": "test-ns", 
    "imageStreamRef": "test-ns/test:latest", 
    "releaseVersion": "master"
  }
}

if err := client.Mutate(context.Background(), &mutation, nil); err !=nil{
    return err
}

// the output
mutation ($input: Input!) {
  addImage(input: $input) {
    numUids
  }
}

In brief, the library uses reflection to get the Go type to build the GraphQL string. Therefore you need to know about the GraphQL schema.

droslean commented 1 year ago

Thanks, @hgiasac. I already tried that too. Here is the error: Message: Expected Name, found !, Locations: [{Line:1 Column:18}]

I tried adding some library debugging logs to see what it's happening. It seems that it's trying to do this query:

mutation ($input:!){addImage(input: $input){numUids}}
hgiasac commented 1 year ago

You need to add a type alias for the $input variable. For example, if the GraphQL schema of the input is:

input SampleInput {
  username: String!
  password: String!
}

you have to define the type alias to the input variable:

type SampleInput map[string]interface{}

variables := map[string]interface{}{
  "input": SampleInput{
    "username": "abc",
    "password": "abc"
  }
}

I don't know what input type schema of the graphql server. You need to find on the source code or graphiql tool

droslean commented 1 year ago

This is exactly what I am doing and still not working. The mutation that the client is trying to do is wrong.

droslean commented 1 year ago

Also, it seems that the bug is in github.com/shurcooL/graphql. Not in this fork.

hgiasac commented 1 year ago

Sorry, I can't reproduce your issue. I guess there is something when wrong with your code. The generation test still works as expected https://github.com/hasura/go-graphql-client/blob/1992b9fa87ab94bcc0719bb1c0d39fd34a2d163e/query_test.go#L370

In your use case, if you use map[string]interface{} or interface{} directly for the input variable, the library will print the empty string

droslean commented 1 year ago

My schema

type Image {
    id: ID!
    name: String!
    namespace: String!
    imageStreamRef: String!
    releaseVersion: String!
    parent(filter: ImageFilter): Image
    childrens(filter: ImageFilter, order: ImageOrder, first: Int, offset: Int): [Image]
    childrensAggregate(filter: ImageFilter): ImageAggregateResult
}

type Mutation {
    addImage(input: [AddImageInput!]!): AddImagePayload
    updateImage(input: UpdateImageInput!): UpdateImagePayload
    deleteImage(filter: ImageFilter!): DeleteImagePayload
}

input AddImageInput {
    name: String!
    namespace: String!
    imageStreamRef: String!
    releaseVersion: String!
    parent: ImageRef
    childrens: [ImageRef]
}
type AddImagePayload {
    image(filter: ImageFilter, order: ImageOrder, first: Int, offset: Int): [Image]
    numUids: Int
}

my code:

    var m struct {
        AddImage struct {
            NumUIDs int `graphql:"numUids"`
        } `graphql:"addImage(input: $input)"`
    }

    type Input []map[string]interface{} // I tried with map[string]interface{} as well, but my input is a list in my schema.
    vars := map[string]interface{}{
        "input": Input{
            {
                "name":           "test",
                "namespace":      "test-ns",
                "imageStreamRef": "test-ns/test:latest",
                "releaseVersion": "master",
            },
        },
    }

    if err := client.Mutate(context.Background(), &m, vars); err != nil {
        return err
    }

So what I am doing wrong?

hgiasac commented 1 year ago

Can you try this code?

var m struct {
    AddImage struct {
        NumUIDs int `graphql:"numUids"`
    } `graphql:"addImage(input: $input)"`
}

type AddImageInput map[string]interface{}
variables := map[string]interface{} {
    "input": []AddImageInput{
        {
            "name":           "test",
            "namespace":      "test-ns",
            "imageStreamRef": "test-ns/test:latest",
            "releaseVersion": "master",
        },
    },
}
droslean commented 1 year ago

ok that worked! Thanks @hgiasac !