Repository: tokio-rs/axum
File: axum/src/routing/path_router.rs (Rust)

Code before:
            let service = Endpoint::MethodRouter(
                prev_method_router
                    .clone()
                    .merge_for_path(Some(path), method_router),
            );
            self.routes.insert(route_id, service);
            return Ok(());
        } else {
            Endpoint::MethodRouter(method_router)
        };

        let id = self.next_route_id();
        self.set_node(path, id)?;
        self.routes.insert(id, endpoint);

        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());
            }
        }
    }

    pub(super) fn route_service<T>(
        &mut self,
        path: &str,
        service: T,
    ) -> Result<(), Cow<'static, str>>
    where
        T: Service<Request, Error = Infallible> + Clone + Send + 'static,
        T::Response: IntoResponse,
        T::Future: Send + 'static,
    {
        self.route_endpoint(path, Endpoint::Route(Route::new(service)))
    }

    pub(super) fn route_endpoint(
        &mut self,
        path: &str,
        endpoint: Endpoint<S>,
    ) -> Result<(), Cow<'static, str>> {
        if path.is_empty() {
            return Err("Paths must start with a `/`. Use \"/\" for root routes".into());
        } else if !path.starts_with('/') {

Review comment (suggestion):
I suggested in #2251 to not use the existing `MethodRouter::fallback` but to have a new method that doesn't overwrite an existing fallback, for cases like this:

```rust
let app = Router::new()
    .route("/", get(index).fallback(root_fallback))
    .route("/foo", /* foo MethodRouter */)
    .route("/bar", /* bar MethodRouter */)
    .route("/baz", /* baz MethodRouter */)
    .method_not_allowed_fallback(resource_mna_fallback);
```

I would argue that people are going to expect `root_fallback` to apply to a `POST /` request, whereas as far as I can tell, this implementation would call `resource_mna_fallback` instead.

Code after:
                ))
            } else {
                None
            }
        })
        .unwrap_or(Ok(()))
}

impl<S, const IS_FALLBACK: bool> PathRouter<S, IS_FALLBACK>
where
    S: Clone + Send + Sync + 'static,
{
    pub(super) fn without_v07_checks(&mut self) {
        self.v7_checks = false;
    }

    pub(super) fn route(
        &mut self,
        path: &str,
        method_router: MethodRouter<S>,
    ) -> Result<(), Cow<'static, str>> {
        validate_path(self.v7_checks, path)?;

        let endpoint = if let Some((route_id, Endpoint::MethodRouter(prev_method_router))) = self
            .node
            .path_to_route_id
            .get(path)
            .and_then(|route_id| self.routes.get(route_id).map(|svc| (*route_id, svc)))
        {
            // if we're adding a new `MethodRouter` to a route that already has one just
            // merge them. This makes `.route("/", get(_)).route("/", post(_))` work
            let service = Endpoint::MethodRouter(
                prev_method_router
                    .clone()
                    .merge_for_path(Some(path), method_router),
            );
            self.routes.insert(route_id, service);
            return Ok(());
        } else {
            Endpoint::MethodRouter(method_router)
        };

        let id = self.next_route_id();
        self.set_node(path, id)?;
        self.routes.insert(id, endpoint);

        Ok(())
    }

    pub(super) fn method_not_allowed_fallback<H, T>(&mut self, handler: H)
    where