-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot retrieve GraphQLResponse
s with ErrorExtensions
properly
#927
Comments
Thanks for the report @bengsparks. This is a tricky one to solve nicely - I could add another generic param to I'll have a think - in the mean time I would recommend just using your own reqwest etc. integration. |
One suggestion I have is to implement a form of delayed evaluation with a builder-esque structure? let response = client
// Prepare to send HTTP request to already running GraphQL server
.get(format!("http://{}/graphql", graphql.host_with_port()))
// Send request with `run_graphql`, WHICH DOES NOT DESERIALIZE YET!
// Instead, store the response as e.g. `reqwest::Error<reqwest::Response>` inside of a
// DelayedResponse<ResponseData>, which is inferrable from the provided arguments.
.run_graphql(FieldWithString::build(FieldWithStringVariables {
input: "InputGoesHere",
}))
// Perform JSON deserialisation here upon `DelayedResponse<ResponseData>::retain_extensions<Extensions>`,
// which contains sufficient type information to deserialise via
// `serde_json::from_str::<GraphQlResponse<ResponseData, Extensions>>`
.retain_extensions::<Extension>(); But ultimately all it does it plug the fact that the |
Ooh, actually that is exactly the right answer, good thinking.
I don't going to have time to implement this immediately but that sounds like the way to go. |
Glad to hear my suggestion could be of use! The only reason I was hesitant to propose this is because of blocking reqwest, which is likely used in non-async environments, and therefore cannot be But perhaps there is a cool solution here too. Or maybe it will have to be the odd one out and require explicit usage. I imagine the majority of cynic's usages are called from async contexts anyhow :) |
#### Why are we making this change? Partially addresses the needs of #927. #### What effects does this change have? Changes the `ReqwestExt` trait to return `CynicReqwestBuilder`. Calling `CynicReqwestBuilder::retain_extensions::<T>` and `await`ing will deserialise the `extensions` field using the shape of T. Directly `await`ing `CynicReqwestBuilder` (i.e. the previous behaviour, thereby maintaining backwards compatibility) will ignore the contents of the "extensions" field. Adds `tokio = { version = "1", features = ["macros"] }` and `mockito = "1.4.0"` to dev dependencies to provide an asynchronous mock server for testing purposes. `cynic/tests/http.rs` provides a comparison of their usages. #### Examples: For a GraphQL server that responds with ```json { "errors": [ { "message": "Unauthorized", "locations": null, "path": [ "helloWorld" ], "extensions": { "code": 401 } } ] } ``` ##### Including `extensions` with `DelayedResponse::retain_extensions` ```rs #[derive(Debug, serde::Deserialize)] struct Extensions { code: u16, } let output = client .get(format!("http://{}/graphql", graphql.host_with_port())) .run_graphql(FieldWithString::build(FieldWithStringVariables { input: "InputGoesHere", })) .retain_extensions::<Extensions>() .await; dbg(!&output); ``` Will produce a response with `extensions: Some(Extensions { code: 401 } )`. ##### Backwards compatible ```rs let client = reqwest::Client::new(); let output = client .get(format!("http://{}/graphql", graphql.host_with_port())) .run_graphql(FieldWithString::build(FieldWithStringVariables { input: "InputGoesHere", })) .await; dbg(!&output); ``` Will produce a response with `extensions: Some(IgnoredAny)`. --------- Co-authored-by: Benjamin Sparks <[email protected]> Co-authored-by: Graeme Coupar <[email protected]>
The traits for extending the request builders of
reqwest
,surf
, etc. all appear like this:Additionally, the definition of a
GraphQLResponse
looks like this:In the first code example, there is no way to specialize the otherwise defaulted
ErrorExtensions
generic argument ofGraphQlResponse
.This implies that attempting to deserialize responses from GraphQL servers, triggered by requests made via these traits, will lead to these extensions being dropped, as per the docs of
serde::de::IgnoredAny
.Likely extending the signatures of
run_graphql
would be sufficient to allow for the additional extension typeI have hacked together an MRE here that demonstrates the issue and provides a new trait to facilitate the desired behaviour with
reqwest
. However, it would mean a breaking change, and the API isn't as nice as I would have liked. Nonetheless, I hope it helps :)The text was updated successfully, but these errors were encountered: