Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions axum-extra/src/routing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,19 @@ pub trait RouterExt<S>: sealed::Sealed {
T: SecondElementIs<P> + 'static,
P: TypedPath;

/// Add a typed `QUERY` route to the router.
///
/// The path will be inferred from the first argument to the handler function which must
/// implement [`TypedPath`].
///
/// See [`TypedPath`] for more details and examples.
#[cfg(feature = "typed-routing")]
fn typed_query<H, T, P>(self, handler: H) -> Self
where
H: axum::handler::Handler<T, S>,
T: SecondElementIs<P> + 'static,
P: TypedPath;

/// Add another route to the router with an additional "trailing slash redirect" route.
///
/// If you add a route _without_ a trailing slash, such as `/foo`, this method will also add a
Expand Down Expand Up @@ -368,6 +381,16 @@ where
self.route(P::PATH, axum::routing::connect(handler))
}

#[cfg(feature = "typed-routing")]
fn typed_query<H, T, P>(self, handler: H) -> Self
where
H: axum::handler::Handler<T, S>,
T: SecondElementIs<P> + 'static,
P: TypedPath,
{
self.route(P::PATH, axum::routing::query(handler))
}

#[track_caller]
fn route_with_tsr(mut self, path: &str, method_router: MethodRouter<S>) -> Self
where
Expand Down
26 changes: 17 additions & 9 deletions axum/src/routing/method_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,25 @@ impl MethodFilter {
/// [extended CONNECT]: https://www.rfc-editor.org/rfc/rfc8441.html#section-4
/// [HTTP Upgrade Token Registry]: https://www.iana.org/assignments/http-upgrade-tokens/http-upgrade-tokens.xhtml
/// [`WebSocketUpgrade`]: crate::extract::WebSocketUpgrade
pub const CONNECT: Self = Self::from_bits(0b0_0000_0001);
pub const CONNECT: Self = Self::from_bits(0b00_0000_0001);
/// Match `DELETE` requests.
pub const DELETE: Self = Self::from_bits(0b0_0000_0010);
pub const DELETE: Self = Self::from_bits(0b00_0000_0010);
/// Match `GET` requests.
pub const GET: Self = Self::from_bits(0b0_0000_0100);
pub const GET: Self = Self::from_bits(0b00_0000_0100);
/// Match `HEAD` requests.
pub const HEAD: Self = Self::from_bits(0b0_0000_1000);
pub const HEAD: Self = Self::from_bits(0b00_0000_1000);
/// Match `OPTIONS` requests.
pub const OPTIONS: Self = Self::from_bits(0b0_0001_0000);
pub const OPTIONS: Self = Self::from_bits(0b00_0001_0000);
/// Match `PATCH` requests.
pub const PATCH: Self = Self::from_bits(0b0_0010_0000);
pub const PATCH: Self = Self::from_bits(0b00_0010_0000);
/// Match `POST` requests.
pub const POST: Self = Self::from_bits(0b0_0100_0000);
pub const POST: Self = Self::from_bits(0b00_0100_0000);
/// Match `PUT` requests.
pub const PUT: Self = Self::from_bits(0b0_1000_0000);
pub const PUT: Self = Self::from_bits(0b00_1000_0000);
/// Match `TRACE` requests.
pub const TRACE: Self = Self::from_bits(0b1_0000_0000);
pub const TRACE: Self = Self::from_bits(0b01_0000_0000);
/// Match `QUERY` requests.
pub const QUERY: Self = Self::from_bits(0b10_0000_0000);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure if the bit mask is meant to follow a certain protocol or it doesn’t matter.


const fn bits(self) -> u16 {
let bits = self;
Expand Down Expand Up @@ -99,6 +101,7 @@ impl TryFrom<Method> for MethodFilter {
Method::POST => Ok(Self::POST),
Method::PUT => Ok(Self::PUT),
Method::TRACE => Ok(Self::TRACE),
Method::QUERY => Ok(Self::QUERY),
other => Err(NoMatchingMethodFilter { method: other }),
}
}
Expand Down Expand Up @@ -155,6 +158,11 @@ mod tests {
MethodFilter::TRACE
);

assert_eq!(
MethodFilter::try_from(Method::QUERY).unwrap(),
MethodFilter::QUERY
);

assert!(
MethodFilter::try_from(http::Method::from_bytes(b"CUSTOM").unwrap())
.unwrap_err()
Expand Down
29 changes: 28 additions & 1 deletion axum/src/routing/method_routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ top_level_service_fn!(patch_service, PATCH);
top_level_service_fn!(post_service, POST);
top_level_service_fn!(put_service, PUT);
top_level_service_fn!(trace_service, TRACE);
top_level_service_fn!(query_service, QUERY);

/// Route requests with the given method to the service.
///
Expand Down Expand Up @@ -445,6 +446,7 @@ top_level_handler_fn!(patch, PATCH);
top_level_handler_fn!(post, POST);
top_level_handler_fn!(put, PUT);
top_level_handler_fn!(trace, TRACE);
top_level_handler_fn!(query, QUERY);

/// Route requests with the given method to the handler.
///
Expand Down Expand Up @@ -554,6 +556,7 @@ pub struct MethodRouter<S = (), E = Infallible> {
put: MethodEndpoint<S, E>,
trace: MethodEndpoint<S, E>,
connect: MethodEndpoint<S, E>,
query: MethodEndpoint<S, E>,
fallback: Fallback<S, E>,
allow_header: AllowHeader,
}
Expand Down Expand Up @@ -595,6 +598,7 @@ impl<S, E> fmt::Debug for MethodRouter<S, E> {
.field("put", &self.put)
.field("trace", &self.trace)
.field("connect", &self.connect)
.field("query", &self.query)
.field("fallback", &self.fallback)
.field("allow_header", &self.allow_header)
.finish()
Expand Down Expand Up @@ -648,6 +652,7 @@ where
chained_handler_fn!(post, POST);
chained_handler_fn!(put, PUT);
chained_handler_fn!(trace, TRACE);
chained_handler_fn!(query, QUERY);

/// Add a fallback [`Handler`] to the router.
pub fn fallback<H, T>(mut self, handler: H) -> Self
Expand Down Expand Up @@ -681,6 +686,7 @@ where
put,
trace,
connect,
query,
fallback,
allow_header: _,
} = self;
Expand All @@ -699,6 +705,7 @@ where
(put, MethodFilter::PUT),
(trace, MethodFilter::TRACE),
(connect, MethodFilter::CONNECT),
(query, MethodFilter::QUERY),
]
.into_iter()
.filter_map(|(ep, f)| ep.is_some().then_some(f))
Expand Down Expand Up @@ -811,6 +818,7 @@ where
put: MethodEndpoint::None,
trace: MethodEndpoint::None,
connect: MethodEndpoint::None,
query: MethodEndpoint::None,
allow_header: AllowHeader::None,
fallback: Fallback::Default(fallback),
}
Expand All @@ -828,6 +836,7 @@ where
put: self.put.with_state(&state),
trace: self.trace.with_state(&state),
connect: self.connect.with_state(&state),
query: self.query.with_state(&state),
allow_header: self.allow_header,
fallback: self.fallback.with_state(state),
}
Expand Down Expand Up @@ -986,6 +995,16 @@ where
&["CONNECT"],
);

set_endpoint(
"QUERY",
&mut self.query,
endpoint,
filter,
MethodFilter::QUERY,
&mut self.allow_header,
&["QUERY"],
);

self
}

Expand All @@ -998,6 +1017,7 @@ where
chained_service_fn!(post_service, POST);
chained_service_fn!(put_service, PUT);
chained_service_fn!(trace_service, TRACE);
chained_service_fn!(query_service, QUERY);

#[doc = include_str!("../docs/method_routing/fallback.md")]
pub fn fallback_service<T>(mut self, svc: T) -> Self
Expand Down Expand Up @@ -1034,6 +1054,7 @@ where
put: self.put.map(layer_fn.clone()),
trace: self.trace.map(layer_fn.clone()),
connect: self.connect.map(layer_fn.clone()),
query: self.query.map(layer_fn.clone()),
fallback: self.fallback.map(layer_fn),
allow_header: self.allow_header,
}
Expand All @@ -1059,6 +1080,7 @@ where
&& self.put.is_none()
&& self.trace.is_none()
&& self.connect.is_none()
&& self.query.is_none()
{
panic!(
"Adding a route_layer before any routes is a no-op. \
Expand All @@ -1076,7 +1098,8 @@ where
self.post = self.post.map(layer_fn.clone());
self.put = self.put.map(layer_fn.clone());
self.trace = self.trace.map(layer_fn.clone());
self.connect = self.connect.map(layer_fn);
self.connect = self.connect.map(layer_fn.clone());
self.query = self.query.map(layer_fn);

self
}
Expand Down Expand Up @@ -1122,6 +1145,7 @@ where
self.put = merge_inner(path, "PUT", self.put, other.put)?;
self.trace = merge_inner(path, "TRACE", self.trace, other.trace)?;
self.connect = merge_inner(path, "CONNECT", self.connect, other.connect)?;
self.query = merge_inner(path, "QUERY", self.query, other.query)?;

self.fallback = self
.fallback
Expand Down Expand Up @@ -1197,6 +1221,7 @@ where
put,
trace,
connect,
query,
fallback,
allow_header,
} = self;
Expand All @@ -1211,6 +1236,7 @@ where
call!(req, DELETE, delete);
call!(req, TRACE, trace);
call!(req, CONNECT, connect);
call!(req, QUERY, query);

let future = fallback.clone().call_with_state(req, state);

Expand Down Expand Up @@ -1254,6 +1280,7 @@ impl<S, E> Clone for MethodRouter<S, E> {
put: self.put.clone(),
trace: self.trace.clone(),
connect: self.connect.clone(),
query: self.query.clone(),
fallback: self.fallback.clone(),
allow_header: self.allow_header.clone(),
}
Expand Down
2 changes: 1 addition & 1 deletion axum/src/routing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub use self::{into_make_service::IntoMakeService, method_filter::MethodFilter,
pub use self::method_routing::{
any, any_service, connect, connect_service, delete, delete_service, get, get_service, head,
head_service, on, on_service, options, options_service, patch, patch_service, post,
post_service, put, put_service, trace, trace_service, MethodRouter,
post_service, put, put_service, trace, trace_service, query, query_service, MethodRouter,
};

macro_rules! panic_on_err {
Expand Down
Loading