55#![ deny( warnings) ]
66#![ deny( missing_docs) ]
77
8+ extern crate itertools;
89extern crate serde;
910#[ macro_use]
1011extern crate serde_derive;
@@ -17,6 +18,9 @@ extern crate serde_json;
1718pub use graphql_query_derive:: * ;
1819
1920use std:: collections:: HashMap ;
21+ use std:: fmt:: { self , Display } ;
22+
23+ use itertools:: Itertools ;
2024
2125/// A convenience trait that can be used to build a GraphQL request body.
2226///
9195}
9296
9397/// Represents a location inside a query string. Used in errors. See [`Error`].
94- #[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
98+ #[ derive( Debug , Clone , Copy , Default , Serialize , Deserialize , PartialEq ) ]
9599pub struct Location {
96100 /// The line number in the query string where the error originated (starting from 1).
97101 pub line : i32 ,
@@ -100,7 +104,7 @@ pub struct Location {
100104}
101105
102106/// Part of a path in a query. It can be an object key or an array index. See [`Error`].
103- #[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
107+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
104108#[ serde( untagged) ]
105109pub enum PathFragment {
106110 /// A key inside an object
@@ -109,6 +113,15 @@ pub enum PathFragment {
109113 Index ( i32 ) ,
110114}
111115
116+ impl Display for PathFragment {
117+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
118+ match * self {
119+ PathFragment :: Key ( ref key) => write ! ( f, "{}" , key) ,
120+ PathFragment :: Index ( ref idx) => write ! ( f, "{}" , idx) ,
121+ }
122+ }
123+ }
124+
112125/// An element in the top-level `errors` array of a response body.
113126///
114127/// This tries to be as close to the spec as possible.
@@ -177,7 +190,7 @@ pub enum PathFragment {
177190/// # Ok(())
178191/// # }
179192/// ```
180- #[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
193+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
181194pub struct Error {
182195 /// The human-readable error message. This is the only required field.
183196 pub message : String ,
@@ -189,6 +202,25 @@ pub struct Error {
189202 pub extensions : Option < HashMap < String , serde_json:: Value > > ,
190203}
191204
205+ impl Display for Error {
206+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
207+ // Use `/` as a separator like JSON Pointer.
208+ let path = self . path
209+ . as_ref ( )
210+ . map ( |fragments| format ! ( "{}" , fragments. iter( ) . format( "/" ) ) )
211+ . unwrap_or_else ( || "<query>" . to_string ( ) ) ;
212+
213+ // Get the location of the error. We'll use just the first location for this.
214+ let loc = self . locations
215+ . as_ref ( )
216+ . and_then ( |locations| locations. iter ( ) . next ( ) )
217+ . cloned ( )
218+ . unwrap_or_else ( Location :: default) ;
219+
220+ write ! ( f, "{}:{}:{}: {}" , path, loc. line, loc. column, self . message)
221+ }
222+ }
223+
192224/// The generic shape taken by the responses of GraphQL APIs.
193225///
194226/// This will generally be used with the `ResponseData` struct from a derived module.
0 commit comments