byme8 / ZeroQL

C# GraphQL client with Linq-like syntax
MIT License
278 stars 13 forks source link

Complex query variables fail to convert #29

Closed YaroslavKormushyn closed 1 year ago

YaroslavKormushyn commented 1 year ago

Describe the bug If a query has a complex-type variable as a filter, any initialization of the variable will fail with a compiler-time error: FailedToConvertPartOfTheQuery Failed to convert to graphql query.

How to Reproduce We have a complex schema like this (cut for brevity):

type Query {
  getItemsPaged(filter: ItemFilter): ItemPage
}

input ItemFilter {
  ids: [UUID]
  name: String
  pageFilter: PageFilter
}

input PageFilter {
  sort: [String]
  page: Int
  size: Int
}

type ItemPage{
  content: [Item]
  size: Int
  number: Int
  totalElements: Int
  totalPages: Int
  numberOfElements: Int
}

type Item{
  id: UUID!
  class: String
  name: String
  comment: JSON
}

Then with the generated client code, the next query won't compile:

var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:10000/graphql");

var client = new TestServerGraphQLClient(httpClient);

var response = await client.Query(static q =>
                q.GetItemsPaged(
                    filter: new ItemFilter { PageFilter = new PageFilter { Page = 0 } },
                    selector: page => new
                    {
                        page.Number,
                        page.TotalPages,
                        Items = page.Content(b => new { Id = b.Id, Name = b.Name, Comment = b.Comment }),
                    })));

Expected behavior The query should compile and the filter variable should be correctly added in the GraphQL query.

Screenshots image

Environment (please complete the following information):

byme8 commented 1 year ago

If you have a complex object, it must be serialized to send a request. If you create it inside the "graphql lambda" ZeroQL doesn't have access to it and can't serialize it before the request. It is a limitation of the current approach.

To make it work you must create an instance before the request and pass it as a variable. Like that:

var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:10000/graphql");

var client = new TestServerGraphQLClient(httpClient);
var variables = new { Filter = new ItemFilter { PageFilter = new PageFilter { Page = 0 } } };
var response = await client.Query(variables, static (i, q) =>
                q.GetItemsPaged(
                    filter: i.Filter,
                    selector: page => new
                    {
                        page.Number,
                        page.TotalPages,
                        Items = page.Content(b => new { Id = b.Id, Name = b.Name, Comment = b.Comment }),
                    })));
YaroslavKormushyn commented 1 year ago

Thanks for the clarification! I have seen this in the example, but the variable has been really simple, so I thought it's something else. I have updated the code and it compiles fine now.