1
0
Fork 0
mirror of https://github.com/tokio-rs/axum.git synced 2025-03-30 11:19:20 +02:00

Write a few docs

This commit is contained in:
David Pedersen 2021-06-06 23:58:44 +02:00
parent 46f74895ce
commit 21c96e0aa1
9 changed files with 441 additions and 72 deletions

View file

@ -14,7 +14,7 @@ use tower_http::{
use tower_web::{
body::Body,
extract::{BytesMaxLength, Extension, UrlParams},
get, route, Handler,
prelude::*,
};
#[tokio::main]

View file

@ -77,6 +77,10 @@ where
}
}
/// A boxed error trait object that implements [`std::error::Error`].
///
/// This is necessary for compatibility with middleware that changes the error
/// type of the response body.
// work around for `BoxError` not implementing `std::error::Error`
//
// This is currently required since tower-http's Compression middleware's body type's

View file

@ -2,7 +2,7 @@ use crate::{
body::{Body, BoxBody},
extract::FromRequest,
response::IntoResponse,
routing::{BoxResponseBody, EmptyRouter, MethodFilter},
routing::{BoxResponseBody, EmptyRouter, MethodFilter, RouteFuture},
service::HandleError,
};
use async_trait::async_trait;
@ -15,7 +15,28 @@ use std::{
marker::PhantomData,
task::{Context, Poll},
};
use tower::{util::Oneshot, BoxError, Layer, Service, ServiceExt};
use tower::{BoxError, Layer, Service, ServiceExt};
pub fn any<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
{
on(MethodFilter::Any, handler)
}
pub fn connect<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
{
on(MethodFilter::Connect, handler)
}
pub fn delete<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
{
on(MethodFilter::Delete, handler)
}
pub fn get<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
@ -24,6 +45,27 @@ where
on(MethodFilter::Get, handler)
}
pub fn head<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
{
on(MethodFilter::Head, handler)
}
pub fn options<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
{
on(MethodFilter::Options, handler)
}
pub fn patch<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
{
on(MethodFilter::Patch, handler)
}
pub fn post<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
@ -31,6 +73,20 @@ where
on(MethodFilter::Post, handler)
}
pub fn put<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
{
on(MethodFilter::Put, handler)
}
pub fn trace<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
{
on(MethodFilter::Trace, handler)
}
pub fn on<H, T>(method: MethodFilter, handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
where
H: Handler<T>,
@ -216,7 +272,7 @@ where
{
type Response = Response<BoxBody>;
type Error = Infallible;
type Future = future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
type Future = IntoServiceFuture;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
// `IntoService` can only be constructed from async functions which are always ready, or from
@ -227,13 +283,19 @@ where
fn call(&mut self, req: Request<Body>) -> Self::Future {
let handler = self.handler.clone();
Box::pin(async move {
let future = Box::pin(async move {
let res = Handler::call(handler, req).await;
Ok(res)
})
});
IntoServiceFuture(future)
}
}
opaque_future! {
pub type IntoServiceFuture =
future::BoxFuture<'static, Result<Response<BoxBody>, Infallible>>;
}
#[derive(Clone)]
pub struct OnMethod<S, F> {
pub(crate) method: MethodFilter,
@ -242,6 +304,27 @@ pub struct OnMethod<S, F> {
}
impl<S, F> OnMethod<S, F> {
pub fn any<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
{
self.on(MethodFilter::Any, handler)
}
pub fn connect<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
{
self.on(MethodFilter::Connect, handler)
}
pub fn delete<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
{
self.on(MethodFilter::Delete, handler)
}
pub fn get<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
@ -249,6 +332,27 @@ impl<S, F> OnMethod<S, F> {
self.on(MethodFilter::Get, handler)
}
pub fn head<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
{
self.on(MethodFilter::Head, handler)
}
pub fn options<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
{
self.on(MethodFilter::Options, handler)
}
pub fn patch<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
{
self.on(MethodFilter::Patch, handler)
}
pub fn post<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
@ -256,6 +360,20 @@ impl<S, F> OnMethod<S, F> {
self.on(MethodFilter::Post, handler)
}
pub fn put<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
{
self.on(MethodFilter::Put, handler)
}
pub fn trace<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
{
self.on(MethodFilter::Trace, handler)
}
pub fn on<H, T>(self, method: MethodFilter, handler: H) -> OnMethod<IntoService<H, T>, Self>
where
H: Handler<T>,
@ -268,8 +386,6 @@ impl<S, F> OnMethod<S, F> {
}
}
// this is identical to `routing::OnMethod`'s implementation. Would be nice to find a way to clean
// that up, but not sure its possible.
impl<S, F, SB, FB> Service<Request<Body>> for OnMethod<S, F>
where
S: Service<Request<Body>, Response = Response<SB>, Error = Infallible> + Clone,
@ -282,24 +398,20 @@ where
{
type Response = Response<BoxBody>;
type Error = Infallible;
#[allow(clippy::type_complexity)]
type Future = future::Either<
BoxResponseBody<Oneshot<S, Request<Body>>>,
BoxResponseBody<Oneshot<F, Request<Body>>>,
>;
type Future = RouteFuture<S, F>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request<Body>) -> Self::Future {
if self.method.matches(req.method()) {
let f = if self.method.matches(req.method()) {
let response_future = self.svc.clone().oneshot(req);
future::Either::Left(BoxResponseBody(response_future))
} else {
let response_future = self.fallback.clone().oneshot(req);
future::Either::Right(BoxResponseBody(response_future))
}
};
RouteFuture(f)
}
}

View file

@ -500,7 +500,6 @@
//! use tower_http::services::ServeFile;
//! use http::Response;
//! use std::convert::Infallible;
//! use tower::{service_fn, BoxError};
//!
//! fn api_routes() -> BoxRoute<BoxBody> {
//! route("/users", get(|_: Request<Body>| async { /* ... */ })).boxed()
@ -571,7 +570,7 @@
rust_2018_idioms,
future_incompatible,
nonstandard_style,
// missing_docs
missing_docs
)]
#![deny(unreachable_pub, broken_intra_doc_links, private_in_public)]
#![allow(
@ -592,6 +591,9 @@ use routing::{EmptyRouter, Route};
use std::convert::Infallible;
use tower::{BoxError, Service};
#[macro_use]
pub(crate) mod macros;
pub mod body;
pub mod extract;
pub mod handler;
@ -602,12 +604,6 @@ pub mod service;
#[cfg(test)]
mod tests;
#[doc(inline)]
pub use self::{
handler::{get, on, post, Handler},
routing::RoutingDsl,
};
pub use async_trait::async_trait;
pub use tower_http::add_extension::{AddExtension, AddExtensionLayer};
@ -615,24 +611,102 @@ pub mod prelude {
//! Re-exports of important traits, types, and functions used with tower-web. Meant to be glob
//! imported.
pub use crate::{
body::Body,
extract,
handler::{get, on, post, Handler},
response, route,
routing::RoutingDsl,
pub use crate::body::Body;
pub use crate::extract;
pub use crate::handler::{
any, connect, delete, get, head, options, patch, post, put, trace, Handler,
};
pub use crate::response;
pub use crate::route;
pub use crate::routing::RoutingDsl;
pub use http::Request;
}
pub fn route<S>(spec: &str, svc: S) -> Route<S, EmptyRouter>
/// Create a route.
///
/// `description` is a string of path segments separated by `/`. Each segment
/// can be either concrete or a capture:
///
/// - `/foo/bar/baz` will only match requests where the path is `/foo/bar/bar`.
/// - `/:foo` will match any route with exactly one segment _and_ it will
/// capture the first segment and store it only the key `foo`.
///
/// `service` is the [`Service`] that should receive the request if the path
/// matches `description`.
///
/// Note that `service`'s error type must be [`Infallible`] meaning you must
/// handle all errors. If you're creating handlers from async functions that is
/// handled automatically but if you're routing to some other [`Service`] you
/// might need to use [`handle_error`](ServiceExt::handle_error) to map errors
/// into responses.
///
/// # Examples
///
/// ```rust
/// use tower_web::prelude::*;
/// # use std::convert::Infallible;
/// # use http::Response;
/// # let service = tower::service_fn(|_: Request<Body>| async {
/// # Ok::<Response<Body>, Infallible>(Response::new(Body::empty()))
/// # });
///
/// route("/", service);
/// route("/users", service);
/// route("/users/:id", service);
/// route("/api/:version/users/:id/action", service);
/// ```
///
/// # Panics
///
/// Panics if `description` doesn't start with `/`.
pub fn route<S>(description: &str, service: S) -> Route<S, EmptyRouter>
where
S: Service<Request<Body>, Error = Infallible> + Clone,
{
routing::EmptyRouter.route(spec, svc)
use routing::RoutingDsl;
routing::EmptyRouter.route(description, service)
}
/// Extension trait that adds additional methods to [`Service`].
pub trait ServiceExt<B>: Service<Request<Body>, Response = Response<B>> {
/// Handle errors from a service.
///
/// tower-web requires all handles to never return errors. If you route to
/// [`Service`], not created by tower-web, who's error isn't `Infallible`
/// you can use this combinator to handle the error.
///
/// `handle_error` takes a closure that will map errors from the service
/// into responses. The closure's return type must implement
/// [`IntoResponse`].
///
/// # Example
///
/// ```rust,no_run
/// use tower_web::{
/// service, prelude::*,
/// ServiceExt,
/// };
/// use http::Response;
/// use tower::{service_fn, BoxError};
///
/// // A service that might fail with `std::io::Error`
/// let service = service_fn(|_: Request<Body>| async {
/// let res = Response::new(Body::empty());
/// Ok::<_, std::io::Error>(res)
/// });
///
/// let app = route(
/// "/",
/// service.handle_error(|error: std::io::Error| {
/// // Handle error by returning something that implements `IntoResponse`
/// }),
/// );
/// #
/// # async {
/// # hyper::Server::bind(&"".parse().unwrap()).serve(tower::make::Shared::new(app)).await;
/// # };
/// ```
fn handle_error<F, Res>(self, f: F) -> service::HandleError<Self, F>
where
Self: Sized,

34
src/macros.rs Normal file
View file

@ -0,0 +1,34 @@
//! Internal macros
macro_rules! opaque_future {
($(#[$m:meta])* pub type $name:ident = $actual:ty;) => {
opaque_future! {
$(#[$m])*
pub type $name<> = $actual;
}
};
($(#[$m:meta])* pub type $name:ident<$($param:ident),*> = $actual:ty;) => {
#[pin_project::pin_project]
$(#[$m])*
pub struct $name<$($param),*>(#[pin] pub(crate) $actual)
where;
impl<$($param),*> std::fmt::Debug for $name<$($param),*> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(stringify!($name)).field(&format_args!("...")).finish()
}
}
impl<$($param),*> std::future::Future for $name<$($param),*>
where
$actual: std::future::Future,
{
type Output = <$actual as std::future::Future>::Output;
#[inline]
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> {
self.project().0.poll(cx)
}
}
};
}

View file

@ -5,7 +5,11 @@ use serde::Serialize;
use std::{borrow::Cow, convert::Infallible};
use tower::util::Either;
/// Trait for generating responses.
///
/// Types that implement `IntoResponse` can be returned from handlers.
pub trait IntoResponse {
/// Create a response.
fn into_response(self) -> Response<Body>;
}
@ -153,6 +157,9 @@ where
}
}
/// An HTML response.
///
/// Will automatically get `Content-Type: text/html`.
pub struct Html<T>(pub T);
impl<T> IntoResponse for Html<T>
@ -167,6 +174,30 @@ where
}
}
/// A JSON response.
///
/// Can be created from any type that implements [`serde::Serialize`].
///
/// Will automatically get `Content-Type: application/json`.
///
/// # Example
///
/// ```
/// use serde_json::json;
/// use tower_web::{body::Body, response::{Json, IntoResponse}};
/// use http::{Response, header::CONTENT_TYPE};
///
/// let json = json!({
/// "data": 42,
/// });
///
/// let response: Response<Body> = Json(json).into_response();
///
/// assert_eq!(
/// response.headers().get(CONTENT_TYPE).unwrap(),
/// "application/json",
/// );
/// ```
pub struct Json<T>(pub T);
impl<T> IntoResponse for Json<T>

View file

@ -64,23 +64,23 @@ pub struct Route<S, F> {
}
pub trait RoutingDsl: Sized {
fn route<T>(self, spec: &str, svc: T) -> Route<T, Self>
fn route<T>(self, description: &str, svc: T) -> Route<T, Self>
where
T: Service<Request<Body>, Error = Infallible> + Clone,
{
Route {
pattern: PathPattern::new(spec),
pattern: PathPattern::new(description),
svc,
fallback: self,
}
}
fn nest<T>(self, spec: &str, svc: T) -> Nested<T, Self>
fn nest<T>(self, description: &str, svc: T) -> Nested<T, Self>
where
T: Service<Request<Body>, Error = Infallible> + Clone,
{
Nested {
pattern: PathPattern::new(spec),
pattern: PathPattern::new(description),
svc,
fallback: self,
}
@ -125,26 +125,50 @@ where
{
type Response = Response<BoxBody>;
type Error = Infallible;
#[allow(clippy::type_complexity)]
type Future = future::Either<
BoxResponseBody<Oneshot<S, Request<Body>>>,
BoxResponseBody<Oneshot<F, Request<Body>>>,
>;
type Future = RouteFuture<S, F>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, mut req: Request<Body>) -> Self::Future {
if let Some(captures) = self.pattern.full_match(req.uri().path()) {
let f = if let Some(captures) = self.pattern.full_match(req.uri().path()) {
insert_url_params(&mut req, captures);
let response_future = self.svc.clone().oneshot(req);
future::Either::Left(BoxResponseBody(response_future))
} else {
let response_future = self.fallback.clone().oneshot(req);
future::Either::Right(BoxResponseBody(response_future))
}
};
RouteFuture(f)
}
}
#[pin_project]
pub struct RouteFuture<S, F>(
#[pin]
pub(crate) future::Either<
BoxResponseBody<Oneshot<S, Request<Body>>>,
BoxResponseBody<Oneshot<F, Request<Body>>>,
>,
)
where
S: Service<Request<Body>>,
F: Service<Request<Body>>;
impl<S, F, SB, FB> Future for RouteFuture<S, F>
where
S: Service<Request<Body>, Response = Response<SB>, Error = Infallible>,
SB: http_body::Body<Data = Bytes> + Send + Sync + 'static,
SB::Error: Into<BoxError>,
F: Service<Request<Body>, Response = Response<FB>, Error = Infallible>,
FB: http_body::Body<Data = Bytes> + Send + Sync + 'static,
FB::Error: Into<BoxError>,
{
type Output = Result<Response<BoxBody>, Infallible>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.project().0.poll(cx)
}
}
@ -187,22 +211,27 @@ pub struct EmptyRouter;
impl RoutingDsl for EmptyRouter {}
impl<R> Service<R> for EmptyRouter {
impl Service<Request<Body>> for EmptyRouter {
type Response = Response<Body>;
type Error = Infallible;
type Future = future::Ready<Result<Self::Response, Self::Error>>;
type Future = EmptyRouterFuture;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _req: R) -> Self::Future {
fn call(&mut self, _req: Request<Body>) -> Self::Future {
let mut res = Response::new(Body::empty());
*res.status_mut() = StatusCode::NOT_FOUND;
future::ok(res)
EmptyRouterFuture(future::ok(res))
}
}
opaque_future! {
pub type EmptyRouterFuture =
future::Ready<Result<Response<Body>, Infallible>>;
}
// ===== PathPattern =====
#[derive(Debug, Clone)]
@ -216,6 +245,11 @@ struct Inner {
impl PathPattern {
pub(crate) fn new(pattern: &str) -> Self {
assert!(
pattern.starts_with('/'),
"Route description must start with a `/`"
);
let mut capture_group_names = Vec::new();
let pattern = pattern
@ -309,7 +343,7 @@ where
{
type Response = Response<BoxBody>;
type Error = Infallible;
type Future = BoxRouteResponseFuture<B>;
type Future = BoxRouteFuture<B>;
#[inline]
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
@ -318,19 +352,19 @@ where
#[inline]
fn call(&mut self, req: Request<Body>) -> Self::Future {
BoxRouteResponseFuture(self.0.clone().oneshot(req))
BoxRouteFuture(self.0.clone().oneshot(req))
}
}
#[pin_project]
pub struct BoxRouteResponseFuture<B>(#[pin] InnerFuture<B>);
pub struct BoxRouteFuture<B>(#[pin] InnerFuture<B>);
type InnerFuture<B> = Oneshot<
Buffer<BoxService<Request<Body>, Response<B>, Infallible>, Request<Body>>,
Request<Body>,
>;
impl<B> Future for BoxRouteResponseFuture<B>
impl<B> Future for BoxRouteFuture<B>
where
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
B::Error: Into<BoxError> + Send + Sync + 'static,
@ -418,12 +452,12 @@ where
// ===== nesting =====
pub fn nest<S>(spec: &str, svc: S) -> Nested<S, EmptyRouter>
pub fn nest<S>(description: &str, svc: S) -> Nested<S, EmptyRouter>
where
S: Service<Request<Body>, Error = Infallible> + Clone,
{
Nested {
pattern: PathPattern::new(spec),
pattern: PathPattern::new(description),
svc,
fallback: EmptyRouter,
}
@ -450,19 +484,14 @@ where
{
type Response = Response<BoxBody>;
type Error = Infallible;
#[allow(clippy::type_complexity)]
type Future = future::Either<
BoxResponseBody<Oneshot<S, Request<Body>>>,
BoxResponseBody<Oneshot<F, Request<Body>>>,
>;
type Future = RouteFuture<S, F>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, mut req: Request<Body>) -> Self::Future {
if let Some((prefix, captures)) = self.pattern.prefix_match(req.uri().path()) {
let f = if let Some((prefix, captures)) = self.pattern.prefix_match(req.uri().path()) {
let without_prefix = strip_prefix(req.uri(), prefix);
*req.uri_mut() = without_prefix;
@ -472,7 +501,8 @@ where
} else {
let response_future = self.fallback.clone().oneshot(req);
future::Either::Right(BoxResponseBody(response_future))
}
};
RouteFuture(f)
}
}

View file

@ -1,7 +1,7 @@
use crate::{
body::{Body, BoxBody},
response::IntoResponse,
routing::{BoxResponseBody, EmptyRouter, MethodFilter},
routing::{BoxResponseBody, EmptyRouter, MethodFilter, RouteFuture},
};
use bytes::Bytes;
use futures_util::future;
@ -17,14 +17,46 @@ use std::{
};
use tower::{util::Oneshot, BoxError, Service, ServiceExt as _};
pub fn any<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Any, svc)
}
pub fn connect<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Connect, svc)
}
pub fn delete<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Delete, svc)
}
pub fn get<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Get, svc)
}
pub fn head<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Head, svc)
}
pub fn options<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Options, svc)
}
pub fn patch<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Patch, svc)
}
pub fn post<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Post, svc)
}
pub fn put<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Put, svc)
}
pub fn trace<S>(svc: S) -> OnMethod<S, EmptyRouter> {
on(MethodFilter::Trace, svc)
}
pub fn on<S>(method: MethodFilter, svc: S) -> OnMethod<S, EmptyRouter> {
OnMethod {
method,
@ -41,6 +73,27 @@ pub struct OnMethod<S, F> {
}
impl<S, F> OnMethod<S, F> {
pub fn any<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
{
self.on(MethodFilter::Any, svc)
}
pub fn connect<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
{
self.on(MethodFilter::Connect, svc)
}
pub fn delete<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
{
self.on(MethodFilter::Delete, svc)
}
pub fn get<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
@ -48,6 +101,27 @@ impl<S, F> OnMethod<S, F> {
self.on(MethodFilter::Get, svc)
}
pub fn head<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
{
self.on(MethodFilter::Head, svc)
}
pub fn options<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
{
self.on(MethodFilter::Options, svc)
}
pub fn patch<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
{
self.on(MethodFilter::Patch, svc)
}
pub fn post<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
@ -55,6 +129,20 @@ impl<S, F> OnMethod<S, F> {
self.on(MethodFilter::Post, svc)
}
pub fn put<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
{
self.on(MethodFilter::Put, svc)
}
pub fn trace<T>(self, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
{
self.on(MethodFilter::Trace, svc)
}
pub fn on<T>(self, method: MethodFilter, svc: T) -> OnMethod<T, Self>
where
T: Service<Request<Body>> + Clone,
@ -81,25 +169,21 @@ where
{
type Response = Response<BoxBody>;
type Error = Infallible;
#[allow(clippy::type_complexity)]
type Future = future::Either<
BoxResponseBody<Oneshot<S, Request<Body>>>,
BoxResponseBody<Oneshot<F, Request<Body>>>,
>;
type Future = RouteFuture<S, F>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request<Body>) -> Self::Future {
if self.method.matches(req.method()) {
let f = if self.method.matches(req.method()) {
let response_future = self.svc.clone().oneshot(req);
future::Either::Left(BoxResponseBody(response_future))
} else {
let response_future = self.fallback.clone().oneshot(req);
future::Either::Right(BoxResponseBody(response_future))
}
};
RouteFuture(f)
}
}

View file

@ -1,4 +1,4 @@
use crate::{extract, get, on, post, route, routing::MethodFilter, service, Handler, RoutingDsl};
use crate::{handler::on, prelude::*, routing::MethodFilter, service};
use http::{Request, Response, StatusCode};
use hyper::{Body, Server};
use serde::Deserialize;