Skip to content

Instantly share code, notes, and snippets.

@mraerino
Created December 30, 2020 00:20
Show Gist options
  • Save mraerino/e7297a73906dbab96d637f6d3f65b934 to your computer and use it in GitHub Desktop.
Save mraerino/e7297a73906dbab96d637f6d3f65b934 to your computer and use it in GitHub Desktop.
use futures::{future, TryFuture};
use std::{marker::PhantomData, net::Ipv6Addr};
use warp::{hyper::StatusCode, reply, Filter, Rejection, Reply};
pub struct ApiBuilder;
pub struct ApiBuilderWithFilter<F, T> {
filter: F,
phantom: PhantomData<T>,
}
impl ApiBuilder {
pub fn new() -> ApiBuilder {
ApiBuilder {}
}
pub fn mount<N, H, Fut, R, T>(
self,
filter: N,
handler: H,
) -> ApiBuilderWithFilter<impl Filter<Error = Rejection, Extract = impl Reply> + Clone, T>
where
N: Filter<Error = Rejection, Extract = (T,)> + Clone + Send,
N::Future: TryFuture,
H: Fn(T) -> Fut + Clone + Send,
Fut: TryFuture<Ok = R, Error = Rejection> + Send,
R: Reply,
{
let action = filter.and_then(handler);
ApiBuilderWithFilter {
filter: action,
phantom: PhantomData,
}
}
}
impl<T, F> ApiBuilderWithFilter<F, T>
where
F: Filter<Error = Rejection> + Clone,
F::Extract: Reply,
{
pub fn mount<N, H, Fut, R, NewT>(
self,
filter: N,
handler: H,
) -> ApiBuilderWithFilter<impl Filter<Error = Rejection, Extract = impl Reply> + Clone, NewT>
where
F::Future: TryFuture,
N: Filter<Error = Rejection, Extract = (NewT,)> + Clone + Send,
N::Future: TryFuture,
H: Fn(NewT) -> Fut + Clone + Send,
Fut: TryFuture<Ok = R, Error = Rejection> + Send,
R: Reply,
{
let action = filter.and_then(handler);
let filter = self.filter.or(action);
ApiBuilderWithFilter {
filter,
phantom: PhantomData,
}
}
pub fn fallback<H, Fut, R>(
self,
handler: H,
) -> ApiBuilderWithFilter<impl Filter<Error = Rejection, Extract = impl Reply> + Clone, ()>
where
H: Fn() -> Fut + Clone + Send,
Fut: TryFuture<Ok = R, Error = Rejection> + Send,
R: Reply,
{
let filter = self.filter.or(warp::any().and_then(handler));
ApiBuilderWithFilter {
filter,
phantom: PhantomData,
}
}
pub fn finish(self) -> F {
self.filter
}
}
#[tokio::main]
async fn main() {
let builder = ApiBuilder::new()
.mount(
warp::path!("hello" / String).and(warp::get()),
|name| async move {
println!("Hello {}", name);
Ok(reply())
},
)
.fallback(|| {
future::ready(Ok::<_, Rejection>(reply::with_status(
reply::html("Not found"),
StatusCode::NOT_FOUND,
)))
});
warp::serve(builder.finish())
.run((Ipv6Addr::LOCALHOST, 3030))
.await;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment