Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add method_not_allowed_fallback to router #2903

Merged
merged 24 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
73ddf83
add method_not_allowed_fallback to router
Lachstec Sep 8, 2024
833daf8
add documentation for method fallback
Lachstec Sep 8, 2024
0617c75
add docs attribute to method fallback
Lachstec Sep 8, 2024
53d75a4
add method_not_allowed_fallback to router
Lachstec Sep 8, 2024
8f97008
add documentation for method fallback
Lachstec Sep 8, 2024
3aedc9a
add docs attribute to method fallback
Lachstec Sep 8, 2024
ce7a42f
Merge branch 'feat/method_fallback' of github.com:Lachstec/axum into …
Lachstec Sep 27, 2024
ff942bc
add no_run to docs for method_not_allowed_fallback
Lachstec Sep 27, 2024
61237da
add option to set fallback if no custom one exists
Lachstec Sep 29, 2024
19b13bb
change method_not_allowed_fallback to use default_fallback
Lachstec Sep 29, 2024
d59d203
switch conditions in match on default fallback
Lachstec Sep 29, 2024
4645f66
test that method_not_allowed_fallback respects previously set fallback
Lachstec Sep 29, 2024
7d2be52
cargo fmt
Lachstec Sep 29, 2024
10c16df
remove typo from docs
Lachstec Sep 29, 2024
bcb2579
remove unnecessary mut
Lachstec Sep 29, 2024
6cd8386
add test for method not allowed fallback with state
Lachstec Sep 29, 2024
6a0d9a2
add another test for method_not_allowed_fallback
Lachstec Oct 11, 2024
546458e
Merge branch 'main' into feat/method_fallback
Lachstec Oct 11, 2024
61f3460
use tap_inner macro and fix tests
Lachstec Oct 11, 2024
a6882c6
Adjust grammar and formatting
Lachstec Oct 12, 2024
da082a5
Better explain how method_not_allowed_fallback works
Lachstec Oct 12, 2024
5c384df
improve grammar and wording
Lachstec Oct 12, 2024
733f0aa
change handle_405 to default_fallback
Lachstec Oct 12, 2024
190a84a
Update axum/src/docs/routing/method_not_allowed_fallback.md
jplatte Oct 12, 2024
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
38 changes: 38 additions & 0 deletions axum/src/docs/routing/method_not_allowed_fallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Add a fallback [`Handler`] for the case where a route exists, but the method of the request is not supported.

Sets the Fallback on the underlying [`MethodRouter`] to be called when it
matches no method.
Lachstec marked this conversation as resolved.
Show resolved Hide resolved

```rust,no_run
use axum::{response::IntoResponse, routing::get, Router};

async fn hello_world() -> impl IntoResponse {
"Hello, world!\n"
}

async fn default_fallback() -> impl IntoResponse {
"Default fallback\n"
}

async fn handle_405() -> impl IntoResponse {
"Method not allowed fallback"
}

#[tokio::main]
async fn main() {
let router = Router::new()
.route("/", get(hello_world))
.fallback(default_fallback)
.method_not_allowed_fallback(handle_405);

let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();

axum::serve(listener, router).await.unwrap();
}
```

The Fallback only applies if there is a MethodRouter registered for the given Route,
Lachstec marked this conversation as resolved.
Show resolved Hide resolved
but the method used in the Request is not specified. In the example, a GET on
Lachstec marked this conversation as resolved.
Show resolved Hide resolved
`http://localhost:3000` causes the `hello_world` handler to react, while issueing a
POST triggers `handle_405`. Calling an entirely different route, like `http://localhost:3000/hello`
jplatte marked this conversation as resolved.
Show resolved Hide resolved
causes `handle_405` to run.
Lachstec marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 12 additions & 0 deletions axum/src/routing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,18 @@ where
.fallback_endpoint(Endpoint::Route(route))
}

#[doc = include_str!("../docs/routing/method_not_allowed_fallback.md")]
pub fn method_not_allowed_fallback<H, T>(self, handler: H) -> Self
where
H: Handler<T, S>,
T: 'static,
{
self.tap_inner_mut(|this| {
this.path_router
.method_not_allowed_fallback(handler.clone())
})
}

fn fallback_endpoint(self, endpoint: Endpoint<S>) -> Self {
self.tap_inner_mut(|this| {
this.fallback_router.set_fallback(endpoint);
Expand Down
17 changes: 16 additions & 1 deletion axum/src/routing/path_router.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::extract::{nested_path::SetNestedPath, Request};
use crate::{
extract::{nested_path::SetNestedPath, Request},
handler::Handler,
};
use axum_core::response::IntoResponse;
use matchit::MatchError;
use std::{borrow::Cow, collections::HashMap, convert::Infallible, fmt, sync::Arc};
Expand Down Expand Up @@ -79,6 +82,18 @@ where
Ok(())
}

pub(super) fn method_not_allowed_fallback<H, T>(&mut self, handler: H)
where
H: Handler<T, S>,
T: 'static,
{
for (_, endpoint) in self.routes.iter_mut() {
if let Endpoint::MethodRouter(rt) = endpoint {
*rt = rt.clone().fallback(handler.clone());
jplatte marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

pub(super) fn route_service<T>(
&mut self,
path: &str,
Expand Down