use async_graphql::*; use futures_util::stream::Stream; #[tokio::test] pub async fn test_fieldresult() { struct Query; #[Object] impl Query { async fn error(&self) -> Result { Err("TestError".into()) } async fn opt_error(&self) -> Option> { Some(Err("TestError".into())) } async fn vec_error(&self) -> Vec> { vec![Ok(1), Err("TestError".into())] } } let schema = Schema::new(Query, EmptyMutation, EmptySubscription); let resp = schema.execute("{ error1:optError error2:optError }").await; assert_eq!( resp.data, value!({ "error1": null, "error2": null, }) ); assert_eq!( resp.errors, vec![ ServerError { message: "TestError".to_string(), source: None, locations: vec![Pos { line: 1, column: 3 }], path: vec![PathSegment::Field("error1".to_owned())], extensions: None, }, ServerError { message: "TestError".to_string(), source: None, locations: vec![Pos { line: 1, column: 19, }], path: vec![PathSegment::Field("error2".to_owned())], extensions: None, }, ] ); assert_eq!( schema .execute("{ optError }") .await .into_result() .unwrap_err(), vec![ServerError { message: "TestError".to_string(), source: None, locations: vec![Pos { line: 1, column: 3 }], path: vec![PathSegment::Field("optError".to_owned())], extensions: None, }] ); assert_eq!( schema .execute("{ vecError }") .await .into_result() .unwrap_err(), vec![ServerError { message: "TestError".to_string(), source: None, locations: vec![Pos { line: 1, column: 3 }], path: vec![ PathSegment::Field("vecError".to_owned()), PathSegment::Index(1) ], extensions: None, }] ); } #[tokio::test] pub async fn test_custom_error() { #[derive(Clone)] struct MyError; impl From for Error { fn from(_: MyError) -> Self { Error::new("custom error") } } #[derive(SimpleObject)] #[graphql(complex)] struct MyObj { value1: i32, } #[ComplexObject] impl MyObj { async fn value2(&self) -> Result { Err(MyError) } } #[derive(Interface)] #[graphql(field(name = "value2", type = "i32"))] enum MyInterface { MyObj(MyObj), } struct Query; #[Object] impl Query { async fn value(&self) -> Result { Err(MyError) } } struct Subscription; #[Subscription] impl Subscription { async fn value1(&self) -> Result, MyError> { Err::>, _>(MyError) } async fn value2(&self) -> impl Stream> { futures_util::stream::once(async move { Err(MyError) }) } } } #[tokio::test] pub async fn test_error_propagation() { struct ParentObject; #[Object] impl ParentObject { async fn child(&self) -> ChildObject { ChildObject } async fn child_opt(&self) -> Option { Some(ChildObject) } } struct ChildObject; #[Object] impl ChildObject { async fn name(&self) -> Result { Err("myerror".into()) } async fn name_opt(&self) -> Option> { Some(Err("myerror".into())) } } struct Query; #[Object] impl Query { async fn parent(&self) -> ParentObject { ParentObject } async fn parent_opt(&self) -> Option { Some(ParentObject) } } let schema = Schema::new(Query, EmptyMutation, EmptySubscription); let resp = schema.execute("{ parent { child { name } } }").await; assert_eq!( resp.errors, vec![ServerError { message: "myerror".to_string(), source: None, locations: vec![Pos { line: 1, column: 20, }], path: vec![ PathSegment::Field("parent".to_owned()), PathSegment::Field("child".to_owned()), PathSegment::Field("name".to_owned()), ], extensions: None, }] ); let resp = schema.execute("{ parent { childOpt { name } } }").await; assert_eq!( resp.data, value!({ "parent": { "childOpt": null, } }) ); assert_eq!( resp.errors, vec![ServerError { message: "myerror".to_string(), source: None, locations: vec![Pos { line: 1, column: 23, }], path: vec![ PathSegment::Field("parent".to_owned()), PathSegment::Field("childOpt".to_owned()), PathSegment::Field("name".to_owned()), ], extensions: None, }] ); let resp = schema.execute("{ parentOpt { child { name } } }").await; assert_eq!(resp.data, value!({ "parentOpt": null })); assert_eq!( resp.errors, vec![ServerError { message: "myerror".to_string(), source: None, locations: vec![Pos { line: 1, column: 23, }], path: vec![ PathSegment::Field("parentOpt".to_owned()), PathSegment::Field("child".to_owned()), PathSegment::Field("name".to_owned()), ], extensions: None, }] ); let resp = schema.execute("{ parentOpt { child { nameOpt } } }").await; assert_eq!( resp.data, value!({ "parentOpt": { "child": { "nameOpt": null, } }, }) ); assert_eq!( resp.errors, vec![ServerError { message: "myerror".to_string(), source: None, locations: vec![Pos { line: 1, column: 23, }], path: vec![ PathSegment::Field("parentOpt".to_owned()), PathSegment::Field("child".to_owned()), PathSegment::Field("nameOpt".to_owned()), ], extensions: None, }] ); }