graphql-client
graphql-client copied to clipboard
Issue with inferring type that implements GraphQLQuery
I am trying to make a generic function to send queries to a server:
fn make_graphql_request<G: GraphQLQuery>(url: &str, query: &QueryBody<G::Variables>) -> Response<G::ResponseData>{
let client = reqwest::Client::new();
let mut res = client
.post(url)
.json(&query)
.send().unwrap();
res.json().unwrap()
}
Then call it on a specific kind of QueryBody:
let q: QueryBody<list_markets_id::Variables> = ListMarketsId::build_query(list_markets_id::Variables);
let res_body = make_graphql_request(&"https://myurl/api/graphql", &q) as Response<list_markets_id::ResponseData>;
What happens is this:
30 | let res_body = make_graphql_request(&"https:/myurl.io/api/graphql", &q) as Response<list_markets_id::ResponseData>;
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type for `G`
What is the type that implements list_markets_id::Variables
and list_markets_id::ResponseDara
? I am new to Rust so I'm sure there must be a simple solution I am missing, but no luck after a few hours of different kinds of annotations. I think it would be useful to add an example that covers this case to the repo. Note that if I change the type signature to the following my code works:
fn make_graphql_request(url: &str, query: &QueryBody<list_markets_id::Variables>) -> Response<list_markets_id::ResponseData>
Thanks for writing up the issue - this should definitely be documented better. I don't have time to look into it in depth today, but to answer your last question ("What is the type that implements list_markets_id::Variables and list_markets_id::ResponseDara?"), it's the struct you annotated with #[derive(GraphQLQuery)]
if you use the derive, or a generated struct with the name of your operation if you use the CLI.
So if your GraphQL file looks like this:
query ListMarketsId { ... }
the CLI will generate a struct called ListMarketsId
that implements GraphQLQuery
(and has the Variables and ResponseData associated types).
I will come back to this and see how we can improve the situation, starting with better docs. Input and ideas are also very much appreciated :)
Thanks @tomhoule, and also for the fast response! Any idea how I can add a type annotation that will make the above work? I did suspect that ListMarketsId
was what implemented it, but am confused why Rust can't infer the G
type in that case.
Also yes, I'd be more than happy to add an example / contribute some docs after figuring this out completely!
I just reread the issue: the problem is that make_graphql_request takes something that implements GraphQLQuery
, but you are passing q
, which is a QueryBody
so inference is impossible. There are 2 ways to fix this:
- Change the signature of make_graphql_request to also take a GraphQLQuery (the G parameter in your example) by value (it's an empty struct) and the associated variables separately, then call build_query from inside make_graphql_request
- Explicitly providing make_graphql_request with the type (circumventing inference), so it would look something like:
let response = make_graphql_query::<ListMarketId>(&"...", &q);
I have to go away from my computer now so I won't be able to reply today, I hope this helps!
Thank you! This is perfect.
I had thought about option (1) but wanted to avoid that approach. Explicitly providing the type on the call is exactly what I was looking for, but I am new enough to Rust that your approach was not obvious to me. Just tested it and it works :)
Happy to circle back on contributing some documentation on this later!