Skip to content

Commit bcf7e7f

Browse files
committed
Make GraphQLError nearly spec-compliant
1 parent 30b6a4d commit bcf7e7f

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## Unreleased
99

10+
## [0.2.0] - 2018-07-22
11+
1012
### Added
1113

1214
- Copy documentation from the GraphQL schema to the generated types (including their fields) as normal Rust documentation. Documentation will show up in the generated docs as well as IDEs that support expanding derive macros (which does not include the RLS yet).
1315
- Implement and test deserializing subscription responses. We also try to provide helpful error messages when a subscription query is not valid (i.e. when it has more than one top-level field).
16+
- Support the [new top-level errors shape from the June 2018 spec](https://github.com/facebook/graphql/blob/master/spec/Section%207%20--%20Response.md), except for the `extensions` field (see issue #64).
1417

1518
### Fixed
1619

src/lib.rs

+85-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ extern crate serde_derive;
88
#[macro_use]
99
extern crate graphql_query_derive;
1010

11+
#[cfg(test)]
12+
#[macro_use]
13+
extern crate serde_json;
14+
1115
#[doc(hidden)]
1216
pub use graphql_query_derive::*;
1317

@@ -29,16 +33,95 @@ where
2933
pub query: &'static str,
3034
}
3135

32-
#[derive(Debug, Serialize, Deserialize)]
36+
#[derive(Debug, Serialize, Deserialize, PartialEq)]
37+
pub struct Location {
38+
line: i32,
39+
column: i32,
40+
}
41+
42+
#[derive(Debug, Serialize, Deserialize, PartialEq)]
43+
#[serde(untagged)]
44+
pub enum PathFragment {
45+
Key(String),
46+
Index(i32),
47+
}
48+
49+
/// An element in the top-level `errors` array of a response body.
50+
///
51+
/// This tries to be as close to the spec as possible.
52+
///
53+
/// Spec: [https://github.com/facebook/graphql/blob/master/spec/Section%207%20--%20Response.md]
54+
#[derive(Debug, Serialize, Deserialize, PartialEq)]
3355
pub struct GraphQLError {
34-
pub path: String,
56+
pub message: String,
57+
pub locations: Option<Vec<Location>>,
58+
pub path: Option<Vec<PathFragment>>,
3559
}
3660

3761
/// The generic shape taken by the responses of GraphQL APIs.
3862
///
3963
/// This will generally be used with the `ResponseData` struct from a derived module.
64+
///
65+
/// Spec: [https://github.com/facebook/graphql/blob/master/spec/Section%207%20--%20Response.md]
4066
#[derive(Debug, Serialize, Deserialize)]
4167
pub struct GraphQLResponse<Data> {
4268
pub data: Option<Data>,
4369
pub errors: Option<Vec<GraphQLError>>,
4470
}
71+
72+
#[cfg(test)]
73+
mod tests {
74+
use super::*;
75+
76+
#[test]
77+
fn graphql_error_works_with_just_message() {
78+
let err = json!({
79+
"message": "I accidentally your whole query"
80+
});
81+
82+
let deserialized_error: GraphQLError = serde_json::from_value(err).unwrap();
83+
84+
assert_eq!(
85+
deserialized_error,
86+
GraphQLError {
87+
message: "I accidentally your whole query".to_string(),
88+
locations: None,
89+
path: None,
90+
}
91+
)
92+
}
93+
94+
#[test]
95+
fn full_graphql_error_deserialization() {
96+
let err = json!({
97+
"message": "I accidentally your whole query",
98+
"locations": [{ "line": 3, "column": 13}, {"line": 56, "column": 1}],
99+
"path": ["home", "alone", 3, "rating"]
100+
});
101+
102+
let deserialized_error: GraphQLError = serde_json::from_value(err).unwrap();
103+
104+
assert_eq!(
105+
deserialized_error,
106+
GraphQLError {
107+
message: "I accidentally your whole query".to_string(),
108+
locations: Some(vec![
109+
Location {
110+
line: 3,
111+
column: 13,
112+
},
113+
Location {
114+
line: 56,
115+
column: 1,
116+
},
117+
]),
118+
path: Some(vec![
119+
PathFragment::Key("home".to_owned()),
120+
PathFragment::Key("alone".to_owned()),
121+
PathFragment::Index(3),
122+
PathFragment::Key("rating".to_owned()),
123+
]),
124+
}
125+
)
126+
}
127+
}

0 commit comments

Comments
 (0)