From 424fb08ecd315c67dd3862c29e87eea7bf32f65c Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Tue, 17 Jun 2025 00:46:24 -0400 Subject: Unify `setup_required` middlewares. The two middlewares were identical but for the specific `IntoResponse` impl used to generate the response when setup has not been completed. However, unifying them while still using `from_fn_with_state` lead to this horrorshow: .route_layer(middleware::from_fn_with_state( app.clone(), |state, req, next| { setup::middeware::setup_required(UNAVAILABLE, state, req, next) } )) It's a lot to read, and it surfaces the entire signature of a state-driven middleware `fn` into the call site solely to close over one argument (`UNAVAILABLE`). Rather than doing that, I've converted this middleware into a full blown Tower middleware, following . I considered taking this further and implementing a custom future to remove the allocation for `Box::pin`, but honestly, that allocation isn't hurting anyone and this code already got long enough in the translation. The new API looks like: .route_layer(setup::Required::or_unavailable(app.clone())) Or like: .route_layer(setup::Required::with_fallback(app.clone(), RESPONSE)) One thing I would have liked to have avoided is the additional `app.clone()` argument, but there isn't a way to extract the _state_ from a request inside of an Axum middleware. It has to be passed in externally - that's what `from_fn_with_state` is doing under the hood, as well. Using `State` as an extractor doesn't work; the `State` extractor is special in a _bunch_ of ways, and this is one of them. Other extractors would work. Realistically, I'd probably want to explore interfaces like .route_layer(setup::Required(app).or_unavailable()) or .route_layer(app.setup().required().or_unavailable()) --- src/setup/middleware.rs | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/setup/middleware.rs (limited to 'src/setup/middleware.rs') diff --git a/src/setup/middleware.rs b/src/setup/middleware.rs deleted file mode 100644 index 5f9996b..0000000 --- a/src/setup/middleware.rs +++ /dev/null @@ -1,20 +0,0 @@ -use axum::{ - extract::{Request, State}, - http::StatusCode, - middleware::Next, - response::{IntoResponse, Response}, -}; - -use crate::{app::App, error::Internal}; - -pub async fn setup_required(State(app): State, request: Request, next: Next) -> Response { - match app.setup().completed().await { - Ok(true) => next.run(request).await, - Ok(false) => ( - StatusCode::SERVICE_UNAVAILABLE, - "initial setup not completed", - ) - .into_response(), - Err(error) => Internal::from(error).into_response(), - } -} -- cgit v1.2.3