Closed
Description
Describe the bug
with juniper_warp = "0.7.0"
, this sequence can happen:
- request comes in with valid
application/json
body. post_json_filter
runs;context_extractor
fails for some transient reason (database error in my case), returns someRejection
that should produce a 5xx error.- then
post_graphql_filter
runs.context_extractor
happens to succeed this time.post_graphql_filter
returns a 4xx rejection about a parse error because the body's actually in json format.
To Reproduce
Steps to reproduce the behavior:
(code example preferred)
failing unit test diff
diff --git a/juniper_warp/src/lib.rs b/juniper_warp/src/lib.rs
index 7b524d2a..7567062f 100644
--- a/juniper_warp/src/lib.rs
+++ b/juniper_warp/src/lib.rs
@@ -449,7 +449,7 @@ pub mod subscriptions {
#[cfg(test)]
mod tests {
use super::*;
- use warp::{http, test::request};
+ use warp::{http, test::request, reject::Reject};
#[test]
fn graphiql_response_does_not_panic() {
@@ -642,6 +642,52 @@ mod tests {
assert!(result.is_err());
}
+
+ #[tokio::test]
+ async fn context_extractor_failure() {
+ use juniper::{
+ tests::fixtures::starwars::schema::{Database, Query},
+ EmptyMutation, EmptySubscription, RootNode,
+ };
+
+ type Schema =
+ juniper::RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;
+
+ let schema: Schema = RootNode::new(
+ Query,
+ EmptyMutation::<Database>::new(),
+ EmptySubscription::<Database>::new(),
+ );
+
+ let called = Arc::new(std::sync::atomic::AtomicBool::new(false));
+ #[derive(Debug)]
+ struct MyRejection;
+ impl Reject for MyRejection {}
+ let context_extractor: warp::filters::BoxedFilter<(Database,)> = warp::any().and_then(move || {
+ std::future::ready(if called.swap(true, std::sync::atomic::Ordering::Relaxed) {
+ println!("second call");
+ Ok(Database::new())
+ } else {
+ println!("first call");
+ Err(warp::reject::custom(MyRejection))
+ })
+ }).boxed();
+ let filter = warp::path("graphql").and(make_graphql_filter(schema, context_extractor));
+ let response = request()
+ .method("POST")
+ .path("/graphql")
+ .header("accept", "application/json")
+ .header("content-type", "application/json")
+ .body(
+ r##"[
+ { "variables": null, "query": "{ hero(episode: NEW_HOPE) { name } }" },
+ { "variables": null, "query": "{ hero(episode: EMPIRE) { id name } }" }
+ ]"##,
+ )
+ .reply(&filter)
+ .await;
+ assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
+ }
}
#[cfg(test)]
Expected behavior
It should run my context_extractor
only once per request. Any Rejection
s returned from the context_extractor
should be returned faithfully from the combined filter returned from make_graphql_filter
, rather than effectively turning a 5xx error into a 4xx error.
Additional context
Add any other context about the problem here.