-
Notifications
You must be signed in to change notification settings - Fork 329
coprocessor: fix parsing of graphql responses with null as data
#7141
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
Changes from all commits
554654e
b7550ec
aa9f029
7093221
2d62b29
a85b32d
5608ca9
b44ca74
1c706e2
2444a2c
2e6e01e
02a9031
9687b0c
5e7e8fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| ### Fix Parsing of Coprocessor GraphQL Responses ([PR #7141](https://github.com/apollographql/router/pull/7141)) | ||
|
|
||
| Previously Router ignored `data: null` property inside GraphQL response returned by coprocessor. | ||
| According to [GraphQL Spectification](https://spec.graphql.org/draft/#sel-FAPHLJCAACEBxlY): | ||
|
|
||
| > If an error was raised during the execution that prevented a valid response, the "data" entry in the response should be null. | ||
|
|
||
| That means if coprocessor returned valid execution error, for example: | ||
|
|
||
| ```json | ||
| { | ||
| "data": null, | ||
| "errors": [{ "message": "Some execution error" }] | ||
| } | ||
| ``` | ||
|
|
||
| Router violated above restriction from GraphQL Specification by returning following response to client: | ||
|
|
||
| ```json | ||
| { | ||
| "errors": [{ "message": "Some execution error" }] | ||
| } | ||
| ``` | ||
|
|
||
| This fix ensures full compliance with the GraphQL specification by preserving the complete structure of error responses from coprocessors. | ||
|
|
||
| Contributed by [@IvanGoncharov](https://github.com/IvanGoncharov) in [#7141](https://github.com/apollographql/router/pull/7141) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ use futures::Stream; | |
| use heck::ToShoutySnakeCase; | ||
| pub use request::Request; | ||
| pub use response::IncrementalResponse; | ||
| use response::MalformedResponseError; | ||
| pub use response::Response; | ||
| use serde::Deserialize; | ||
| use serde::Serialize; | ||
|
|
@@ -21,7 +22,6 @@ use serde_json_bytes::Map as JsonMap; | |
| use serde_json_bytes::Value; | ||
| pub(crate) use visitor::ResponseVisitor; | ||
|
|
||
| use crate::error::FetchError; | ||
| use crate::json_ext::Object; | ||
| use crate::json_ext::Path; | ||
| pub use crate::json_ext::Path as JsonPath; | ||
|
|
@@ -125,41 +125,39 @@ impl Error { | |
| } | ||
| } | ||
|
|
||
| pub(crate) fn from_value(service_name: &str, value: Value) -> Result<Error, FetchError> { | ||
| let mut object = | ||
| ensure_object!(value).map_err(|error| FetchError::SubrequestMalformedResponse { | ||
| service: service_name.to_string(), | ||
| reason: format!("invalid error within `errors`: {}", error), | ||
| })?; | ||
| pub(crate) fn from_value(value: Value) -> Result<Error, MalformedResponseError> { | ||
| let mut object = ensure_object!(value).map_err(|error| MalformedResponseError { | ||
| reason: format!("invalid error within `errors`: {}", error), | ||
| })?; | ||
|
|
||
| let extensions = | ||
| extract_key_value_from_object!(object, "extensions", Value::Object(o) => o) | ||
| .map_err(|err| FetchError::SubrequestMalformedResponse { | ||
| service: service_name.to_string(), | ||
| .map_err(|err| MalformedResponseError { | ||
| reason: format!("invalid `extensions` within error: {}", err), | ||
| })? | ||
| .unwrap_or_default(); | ||
| let message = extract_key_value_from_object!(object, "message", Value::String(s) => s) | ||
| .map_err(|err| FetchError::SubrequestMalformedResponse { | ||
| service: service_name.to_string(), | ||
| let message = match extract_key_value_from_object!(object, "message", Value::String(s) => s) | ||
| { | ||
| Ok(Some(s)) => Ok(s.as_str().to_string()), | ||
| Ok(None) => Err(MalformedResponseError { | ||
| reason: "missing required `message` property within error".to_owned(), | ||
| }), | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a new behaviour for subgraph response parsing.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it potentially a breaking change or could it break existing implementation ? I think it's a bug fix but as it's more strict maybe it could be interesting to add notes about this in the changelog to avoid confusions |
||
| Err(err) => Err(MalformedResponseError { | ||
| reason: format!("invalid `message` within error: {}", err), | ||
| })? | ||
| .map(|s| s.as_str().to_string()) | ||
| .unwrap_or_default(); | ||
| }), | ||
| }?; | ||
| let locations = extract_key_value_from_object!(object, "locations") | ||
| .map(skip_invalid_locations) | ||
| .map(serde_json_bytes::from_value) | ||
| .transpose() | ||
| .map_err(|err| FetchError::SubrequestMalformedResponse { | ||
| service: service_name.to_string(), | ||
| .map_err(|err| MalformedResponseError { | ||
| reason: format!("invalid `locations` within error: {}", err), | ||
| })? | ||
| .unwrap_or_default(); | ||
| let path = extract_key_value_from_object!(object, "path") | ||
| .map(serde_json_bytes::from_value) | ||
| .transpose() | ||
| .map_err(|err| FetchError::SubrequestMalformedResponse { | ||
| service: service_name.to_string(), | ||
| .map_err(|err| MalformedResponseError { | ||
| reason: format!("invalid `path` within error: {}", err), | ||
| })?; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.