Skip to content

Commit

Permalink
Allow routes to return anyhow::Error
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaseizinger committed May 26, 2020
1 parent 74dda30 commit deda6f2
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ edition = "2018"
all-features = true

[dependencies]
anyhow = { version = "1", optional = true }
async-compression = { version = "0.3.1", features = ["brotli", "deflate", "gzip", "stream"], optional = true }
bytes = "0.5"
futures = { version = "0.3", default-features = false, features = ["alloc"] }
Expand Down Expand Up @@ -83,3 +84,7 @@ required-features = ["websocket"]
[[example]]
name = "websockets_chat"
required-features = ["websocket"]

[[example]]
name = "anyhow"
required-features = ["anyhow"]
61 changes: 61 additions & 0 deletions examples/anyhow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#![deny(warnings)]

use serde::export::Formatter;
use warp::http::StatusCode;
use warp::{Filter, Rejection, Reply};

#[tokio::main]
async fn main() {
let is_even = warp::path!("is_even" / u64).and_then(handler);

let routes = warp::get().and(is_even).recover(handle_rejection);

warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}

async fn handler(number: u64) -> anyhow::Result<impl Reply> {
if number > 100 {
anyhow::bail!(TooBig)
}

if number % 2 == 1 {
anyhow::bail!(NotEven)
}

return Ok(StatusCode::OK);
}

#[derive(Debug)]
struct TooBig;

impl std::fmt::Display for TooBig {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "sorry, we can't handle big numbers like this")
}
}

#[derive(Debug)]
struct NotEven;

impl std::fmt::Display for NotEven {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "the given number is not even")
}
}

async fn handle_rejection(err: Rejection) -> Result<impl Reply, Rejection> {
if let Some(anyhow) = err.find::<anyhow::Error>() {
// here we can downcast the anyhow error to whatever we want
if let Some(_) = anyhow.downcast_ref::<TooBig>() {
return Ok(StatusCode::INTERNAL_SERVER_ERROR);
}

if let Some(_) = anyhow.downcast_ref::<NotEven>() {
return Ok(StatusCode::BAD_REQUEST);
}

return Ok(StatusCode::INTERNAL_SERVER_ERROR);
}

Err(err)
}
50 changes: 50 additions & 0 deletions src/reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ impl dyn Cause {
}
}

#[cfg(feature = "anyhow")]
impl Reject for anyhow::Error {}

#[cfg(feature = "anyhow")]
impl From<anyhow::Error> for Rejection {
fn from(anyhow: anyhow::Error) -> Self {
custom(anyhow)
}
}

pub(crate) fn known<T: Into<Known>>(err: T) -> Rejection {
Rejection::known(err.into())
}
Expand Down Expand Up @@ -659,6 +669,46 @@ mod sealed {
match self {}
}
}

#[cfg(feature = "anyhow")]
impl CombineRejection<anyhow::Error> for Infallible {
type One = Rejection;
type Combined = Rejection;

fn combine(self, anyhow: anyhow::Error) -> Self::Combined {
crate::reject::custom(anyhow)
}
}

#[cfg(feature = "anyhow")]
impl CombineRejection<Infallible> for anyhow::Error {
type One = Rejection;
type Combined = Rejection;

fn combine(self, _: Infallible) -> Self::Combined {
crate::reject::custom(self)
}
}

#[cfg(feature = "anyhow")]
impl CombineRejection<anyhow::Error> for Rejection {
type One = Rejection;
type Combined = Rejection;

fn combine(self, e: anyhow::Error) -> Self::Combined {
self.combine(crate::reject::custom(e))
}
}

#[cfg(feature = "anyhow")]
impl CombineRejection<Rejection> for anyhow::Error {
type One = Rejection;
type Combined = Rejection;

fn combine(self, rejection: Rejection) -> Self::Combined {
rejection.combine(crate::reject::custom(self))
}
}
}

#[cfg(test)]
Expand Down

0 comments on commit deda6f2

Please sign in to comment.