Use 'extensions' as field for error details (#219)

This commit is contained in:
Damir Vandic 2018-08-13 15:53:52 +02:00 committed by Christian Legnitto
parent 90b89f00ee
commit ec59766d51
4 changed files with 32 additions and 12 deletions

View file

@ -38,3 +38,9 @@
* `GraphQLType` and `ToInputValue` are now implemented for Arc<T>
[#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)

View file

@ -127,14 +127,14 @@ impl Ord for ExecutionError {
#[derive(Debug, PartialEq)]
pub struct FieldError {
message: String,
data: Value,
extensions: Value,
}
impl<T: Display> From<T> for FieldError {
fn from(e: T) -> FieldError {
FieldError {
message: format!("{}", e),
data: Value::null(),
extensions: Value::null(),
}
}
}
@ -157,7 +157,7 @@ impl FieldError {
/// # 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:
///
/// ```json
@ -165,7 +165,7 @@ impl FieldError {
/// "errors": [
/// "message": "Could not open connection to the database",
/// "locations": [{"line": 2, "column": 4}],
/// "data": {
/// "extensions": {
/// "internal_error": "Connection refused"
/// }
/// ]
@ -173,10 +173,10 @@ impl FieldError {
/// ```
///
/// 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 {
message: format!("{}", e),
data: data,
extensions,
}
}
@ -186,8 +186,8 @@ impl FieldError {
}
#[doc(hidden)]
pub fn data(&self) -> &Value {
&self.data
pub fn extensions(&self) -> &Value {
&self.extensions
}
}

View file

@ -32,9 +32,9 @@ impl ser::Serialize for ExecutionError {
map.serialize_key("path")?;
map.serialize_value(self.path())?;
if !self.error().data().is_null() {
map.serialize_key("data")?;
map.serialize_value(self.error().data())?;
if !self.error().extensions().is_null() {
map.serialize_key("extensions")?;
map.serialize_value(self.error().extensions())?;
}
map.end()
@ -285,10 +285,11 @@ impl ser::Serialize for Value {
#[cfg(test)]
mod tests {
use super::GraphQLError;
use super::{ExecutionError, GraphQLError};
use ast::InputValue;
use serde_json::from_str;
use serde_json::to_string;
use {FieldError, Value};
#[test]
fn int() {
@ -318,4 +319,15 @@ mod tests {
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"}}"#
);
}
}

View file

@ -98,6 +98,8 @@ extern crate serde_derive;
extern crate serde_json;
extern crate fnv;
#[cfg_attr(test, macro_use)]
extern crate indexmap;
#[cfg(any(test, feature = "chrono"))]