1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use {
    http::{Response, StatusCode},
    serde_json::json,
    tsukuyomi::{
        error::{Error, HttpError}, //
        future::{Async, Poll, TryFuture},
        handler::{Handler, ModifyHandler},
        input::Input,
        output::IntoResponse,
        util::Either,
    },
};

#[derive(Debug, failure::Fail)]
pub enum GraphQLParseError {
    #[fail(display = "the request method is invalid")]
    InvalidRequestMethod,
    #[fail(display = "missing query")]
    MissingQuery,
    #[fail(display = "missing content-type")]
    MissingMime,
    #[fail(display = "the content type is invalid.")]
    InvalidMime,
    #[fail(display = "failed to parse input as a JSON object")]
    ParseJson(#[fail(cause)] serde_json::Error),
    #[fail(display = "failed to parse HTTP query")]
    ParseQuery(#[fail(cause)] serde_urlencoded::de::Error),
    #[fail(display = "failed to decode input as a UTF-8 sequence")]
    DecodeUtf8(#[fail(cause)] std::str::Utf8Error),
}

impl HttpError for GraphQLParseError {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

/// Creates a `ModifyHandler` that catches the all kind of errors that the handler throws
/// and converts them into GraphQL errors.
pub fn capture_errors() -> CaptureErrors {
    CaptureErrors(())
}

#[allow(missing_docs)]
#[derive(Debug)]
pub struct CaptureErrors(());

impl<H> ModifyHandler<H> for CaptureErrors
where
    H: Handler,
{
    type Output = Either<Response<String>, H::Output>;
    type Error = Error;
    type Handler = CaptureErrorsHandler<H>; // private;

    fn modify(&self, inner: H) -> Self::Handler {
        CaptureErrorsHandler { inner }
    }
}

#[derive(Debug)]
pub struct CaptureErrorsHandler<H> {
    inner: H,
}

impl<H> Handler for CaptureErrorsHandler<H>
where
    H: Handler,
{
    type Output = Either<Response<String>, H::Output>;
    type Error = Error;
    type Handle = CaptureErrorsHandle<H::Handle>;

    fn handle(&self) -> Self::Handle {
        CaptureErrorsHandle {
            inner: self.inner.handle(),
        }
    }
}

#[derive(Debug)]
pub struct CaptureErrorsHandle<H> {
    inner: H,
}

impl<H> TryFuture for CaptureErrorsHandle<H>
where
    H: TryFuture,
{
    type Ok = Either<Response<String>, H::Ok>;
    type Error = Error;

    #[inline]
    fn poll_ready(&mut self, input: &mut Input<'_>) -> Poll<Self::Ok, Self::Error> {
        match self.inner.poll_ready(input) {
            Ok(Async::Ready(ok)) => Ok(Async::Ready(Either::Right(ok))),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(err) => {
                let err = err.into();
                let body = json!({
                    "errors": [
                        {
                            "message": err.to_string(),
                        }
                    ],
                })
                .to_string();

                let mut response = err.into_response().map(|_| body.into());
                response.headers_mut().insert(
                    http::header::CONTENT_TYPE,
                    http::header::HeaderValue::from_static("application/json"),
                );

                Ok(Async::Ready(Either::Left(response)))
            }
        }
    }
}