Use 'extensions' as field for error details (#219)
This commit is contained in:
parent
90b89f00ee
commit
ec59766d51
4 changed files with 32 additions and 12 deletions
|
@ -38,3 +38,9 @@
|
||||||
* `GraphQLType` and `ToInputValue` are now implemented for Arc<T>
|
* `GraphQLType` and `ToInputValue` are now implemented for Arc<T>
|
||||||
|
|
||||||
[#212](https://github.com/graphql-rust/juniper/pull/212)
|
[#212](https://github.com/graphql-rust/juniper/pull/212)
|
||||||
|
|
||||||
|
* Error responses no longer have a *data* field, instead, error details are stored in the *extensions* field
|
||||||
|
|
||||||
|
**Note:** while this is a breaking change, it is a necessary one to better align with the latest [GraphQL June 2018](https://facebook.github.io/graphql/June2018/#sec-Errors) specification, which defines the reserved *extensions* field for error details.
|
||||||
|
|
||||||
|
[#219](https://github.com/graphql-rust/juniper/pull/219)
|
||||||
|
|
|
@ -127,14 +127,14 @@ impl Ord for ExecutionError {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct FieldError {
|
pub struct FieldError {
|
||||||
message: String,
|
message: String,
|
||||||
data: Value,
|
extensions: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Display> From<T> for FieldError {
|
impl<T: Display> From<T> for FieldError {
|
||||||
fn from(e: T) -> FieldError {
|
fn from(e: T) -> FieldError {
|
||||||
FieldError {
|
FieldError {
|
||||||
message: format!("{}", e),
|
message: format!("{}", e),
|
||||||
data: Value::null(),
|
extensions: Value::null(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ impl FieldError {
|
||||||
/// # fn main() { }
|
/// # fn main() { }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The `data` parameter will be added to the `"data"` field of the error
|
/// The `extensions` parameter will be added to the `"extensions"` field of the error
|
||||||
/// object in the JSON response:
|
/// object in the JSON response:
|
||||||
///
|
///
|
||||||
/// ```json
|
/// ```json
|
||||||
|
@ -165,7 +165,7 @@ impl FieldError {
|
||||||
/// "errors": [
|
/// "errors": [
|
||||||
/// "message": "Could not open connection to the database",
|
/// "message": "Could not open connection to the database",
|
||||||
/// "locations": [{"line": 2, "column": 4}],
|
/// "locations": [{"line": 2, "column": 4}],
|
||||||
/// "data": {
|
/// "extensions": {
|
||||||
/// "internal_error": "Connection refused"
|
/// "internal_error": "Connection refused"
|
||||||
/// }
|
/// }
|
||||||
/// ]
|
/// ]
|
||||||
|
@ -173,10 +173,10 @@ impl FieldError {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If the argument is `Value::null()`, no extra data will be included.
|
/// If the argument is `Value::null()`, no extra data will be included.
|
||||||
pub fn new<T: Display>(e: T, data: Value) -> FieldError {
|
pub fn new<T: Display>(e: T, extensions: Value) -> FieldError {
|
||||||
FieldError {
|
FieldError {
|
||||||
message: format!("{}", e),
|
message: format!("{}", e),
|
||||||
data: data,
|
extensions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,8 +186,8 @@ impl FieldError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn data(&self) -> &Value {
|
pub fn extensions(&self) -> &Value {
|
||||||
&self.data
|
&self.extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,9 @@ impl ser::Serialize for ExecutionError {
|
||||||
map.serialize_key("path")?;
|
map.serialize_key("path")?;
|
||||||
map.serialize_value(self.path())?;
|
map.serialize_value(self.path())?;
|
||||||
|
|
||||||
if !self.error().data().is_null() {
|
if !self.error().extensions().is_null() {
|
||||||
map.serialize_key("data")?;
|
map.serialize_key("extensions")?;
|
||||||
map.serialize_value(self.error().data())?;
|
map.serialize_value(self.error().extensions())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
map.end()
|
map.end()
|
||||||
|
@ -285,10 +285,11 @@ impl ser::Serialize for Value {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::GraphQLError;
|
use super::{ExecutionError, GraphQLError};
|
||||||
use ast::InputValue;
|
use ast::InputValue;
|
||||||
use serde_json::from_str;
|
use serde_json::from_str;
|
||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
|
use {FieldError, Value};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn int() {
|
fn int() {
|
||||||
|
@ -318,4 +319,15 @@ mod tests {
|
||||||
r#"[{"message":"Unknown operation"}]"#
|
r#"[{"message":"Unknown operation"}]"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_extensions() {
|
||||||
|
assert_eq!(
|
||||||
|
to_string(&ExecutionError::at_origin(FieldError::new(
|
||||||
|
"foo error",
|
||||||
|
Value::Object(indexmap!{"foo".to_string() => Value::String("bar".to_string())}),
|
||||||
|
))).unwrap(),
|
||||||
|
r#"{"message":"foo error","locations":[{"line":1,"column":1}],"path":[],"extensions":{"foo":"bar"}}"#
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,8 @@ extern crate serde_derive;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
extern crate fnv;
|
extern crate fnv;
|
||||||
|
|
||||||
|
#[cfg_attr(test, macro_use)]
|
||||||
extern crate indexmap;
|
extern crate indexmap;
|
||||||
|
|
||||||
#[cfg(any(test, feature = "chrono"))]
|
#[cfg(any(test, feature = "chrono"))]
|
||||||
|
|
Loading…
Reference in a new issue