Hi team. I'm new to rust and trying to build a websocket application on top of axum. I modify the chat example with an additional middleware (layer) to determine if the websocket connection should be established or not.
When the check function with return type Result<T, Box<dyn Error>>
is invoked and the returned value is taken, the compiler reports that there's trait bound unsatisfied, while if not taking the return value (let _ = check()
), or with the return type Result<T, ()>
, then everything is fine.
Could you help to explain where this error comes from, and is there any best practice for axum middleware error handling for custom type of Error? Thank you.
Here's the simplified code:
use std::net::SocketAddr;
use std::error::Error;
use axum::{extract::{
ws::{WebSocket, WebSocketUpgrade},
}, response::IntoResponse, routing::any};
use axum::http::{Request, StatusCode};
use axum::middleware::{from_fn, Next};
use axum::response::Response;
use axum::Router;
#[tokio::test]
async fn main() {
let app = Router::new()
.route("/chat",
any(ws_handler)
.layer(from_fn(check_something)));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn check_something<B>(
request: Request<B>,
next: Next<B>,
) -> Response {
// Not invoke do_check_bad : everything ok
let _ = do_check_bad(); // everything ok
let good_res = do_check_good(); // everything ok
let bad_res = do_check_bad(); // trait bound error
match bad_res {
Ok(_) => {}
Err(_) => { return (StatusCode::BAD_REQUEST, "err").into_response() }
}
let response = next.run(request).await;
response
}
fn do_check_bad() -> Result<String, Box<dyn Error>> // BAD
{
return Err(Box::new(std::fmt::Error/*any kind of err*/ {}));
}
fn do_check_good() -> Result<String, ()> // GOOD
{
return Err(());
}
async fn ws_handler(
ws: WebSocketUpgrade,
) -> impl IntoResponse {
ws.on_upgrade(|socket| websocket(socket))
}
async fn websocket(stream: WebSocket) {}
Here's the error message:
error[E0277]: the trait bound `axum::middleware::FromFn<fn(Request<_>, axum::middleware::Next<_>) -> impl futures::Future<Output = Response<http_body::combinators::box_body::UnsyncBoxBody<bytes::Bytes, axum::Error>>> {check_something::<_>}, (), Route<_>, _>: Service<Request<_>>` is not satisfied
--> src\chat_copy.rs:25:27
|
25 | .layer(from_fn(check_something)));
| ----- ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Service<Request<_>>` is not implemented for `axum::middleware::FromFn<fn(Request<_>, axum::middleware::Next<_>) -> impl futures::Future<Output = Response<http_body::combinators::box_body::UnsyncBoxBody<bytes::Bytes, axum::Error>>> {check_something::<_>}, (), Route<_>, _>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Service<Request>`:
axum::middleware::FromFn<F, S, I, (T1,)>
axum::middleware::FromFn<F, S, I, (T1, T2)>
axum::middleware::FromFn<F, S, I, (T1, T2, T3)>
axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4)>
axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4, T5)>
axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4, T5, T6)>
axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4, T5, T6, T7)>
axum::middleware::FromFn<F, S, I, (T1, T2, T3, T4, T5, T6, T7, T8)>
and 8 others
note: required by a bound in `MethodRouter::<S, B, E>::layer`
--> C:\Users\user\.cargo\registry\src\some_registry\axum-0.6.20\src\routing\method_routing.rs:923:21
|
920 | pub fn layer<L, NewReqBody, NewError>(self, layer: L) -> MethodRouter<S, NewReqBody, NewError>
| ----- required by a bound in this associated function
...
923 | L::Service: Service<Request<NewReqBody>> + Clone + Send + 'static,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `MethodRouter::<S, B, E>::layer`