Created
March 15, 2019 12:34
-
-
Save romac/012d78e0a2b21737ef50129826008614 to your computer and use it in GitHub Desktop.
Rocket + frunk Coproduct for type-safe route results
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type TestRes = RouteResult< | |
Created<JsonValue>, | |
Coprod!( | |
BadRequest<JsonValue>, | |
NotFound<JsonValue>, | |
InternalServerError<JsonValue> | |
), | |
>; | |
#[post("/test/<a>")] | |
pub fn test(a: u32) -> TestRes { | |
if a < 0 { | |
return Route::err(BadRequest(JsonValue(json!({ | |
"status": "error", | |
"type": "Negative number", | |
})))); | |
} | |
if a == 0 { | |
return Route::err(NotFound(JsonValue(json!({ | |
"status": "error", | |
"type": "NotFound", | |
"reason": "Not found with a = 0", | |
})))); | |
} | |
if a != 42 { | |
return RouteResult::err(InternalServerError(JsonValue(json!({ | |
"status": "error", | |
"type": "Not42", | |
"reason": "Not equal 42" })))); | |
} | |
RouteResult::ok(Created( | |
uri!("/view", view: a = a).to_string(), | |
Some(JsonValue(json!({ | |
"status": "success", | |
"a": a, | |
}))), | |
)) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::result::Result as StdResult; | |
use frunk::coproduct::*; | |
use rocket::http::Status; | |
use rocket::request::Request; | |
use rocket::response::{Responder, Response, Result}; | |
pub struct Route<A, B>(StdResult<A, RouteErr<B>>); | |
impl<A, B> Route<A, B> { | |
pub fn ok(a: A) -> Self { | |
Self(Ok(a)) | |
} | |
pub fn err<T, I>(i: I) -> Self | |
where | |
B: CoprodInjector<I, T>, | |
{ | |
Self(Err(RouteErr::new(i))) | |
} | |
} | |
impl<'r, A, B> Responder<'r> for Route<A, B> | |
where | |
A: Responder<'r>, | |
RouteErr<B>: Responder<'r>, | |
{ | |
fn respond_to(self, request: &Request) -> Result<'r> { | |
match self.0 { | |
Ok(a) => a.respond_to(request), | |
Err(b) => b.respond_to(request), | |
} | |
} | |
} | |
pub struct RouteErr<E>(pub E); | |
impl<E> RouteErr<E> { | |
pub fn new<T, I>(t: T) -> Self | |
where | |
E: CoprodInjector<T, I>, | |
{ | |
RouteErr(E::inject(t)) | |
} | |
} | |
impl<'r> Responder<'r> for RouteErr<CNil> { | |
fn respond_to(self, request: &Request) -> Result<'r> { | |
InternalServerError::<JsonValue>(None).respond_to(request) | |
} | |
} | |
impl<'r, H, T> Responder<'r> for RouteErr<Coproduct<H, T>> | |
where | |
H: Responder<'r>, | |
RouteErr<T>: Responder<'r>, | |
{ | |
fn respond_to(self, request: &Request) -> Result<'r> { | |
match self.0 { | |
Coproduct::Inl(l) => l.respond_to(request), | |
Coproduct::Inr(r) => RouteErr(r).respond_to(request), | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment