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
Router::with_state_arc
might be misleading
#1321
Comments
Yeah I see what the problem is 😕 A silly workaround is to extract use axum::{extract::State, routing::get, Router};
use std::sync::Arc;
struct UnclonableExample(usize);
#[tokio::main]
async fn main() {
let state = UnclonableExample(42);
let state_arc = Arc::new(state);
let router: Router<_> = Router::with_state_arc(state_arc).route("/", get(handler));
}
#[axum::debug_handler]
async fn handler(State(state): State<Arc<Arc<UnclonableExample>>>) {} This isn't great and something we try and address. |
With that said This this issue is about removing the double |
Honestly that seems to be the fix. Making your state #[derive(Clone)] // <---
struct UnclonableExample(usize);
#[tokio::main]
async fn main() {
let state = UnclonableExample(42);
let state_arc = Arc::new(state);
let router: Router<_> = Router::with_state_arc(state_arc).route("/", get(handler));
}
async fn handler(State(state): State<UnclonableExample>) {} |
Sure, that's possible in this case, but not everything is |
The You can always wrap your state in an Arc and use let state_arc = Arc::new(state);
let router: Router<_> = Router::with_state(state_arc).route("/", get(handler));
async fn handler(State(state): State<Arc<UnclonableExample>>) {} |
Yeah, that works! And thinking more about it... realistically, one would probably put I'll close this. Thanks for your time! ❤️ |
I'll keep this open because I think its worth documenting. |
This remains confusing to me. I'm moving my app to Here's a minimal example of my problem: I can't seem to figure out how to make the compiler happy with the following (should be easy to build stand-alone, depends on e.g. uuid and axum 0.6.0-rc.1 only I think): use axum::Router;
use serde_derive::Deserialize;
use axum::{
extract::{Path, State},
response::{Html, IntoResponse, Response},
routing::get,
Form,
};
use std::net::SocketAddr;
use uuid::Uuid;
#[derive(Default)]
struct AppState {
// More stuff here but we have just a String (clonable)
important: String,
}
#[tokio::main]
async fn main() {
// The State for our application
let state: AppState = AppState::default();
// build our application with a route
let app = Router::with_state(state)
.route("/", get(get_index))
.route("/entity/:entity_id", get(get_entity).post(post_entity));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
#[derive(Deserialize)]
struct PlayForm {
play: String,
}
async fn get_entity(Path(entity_id): Path<Uuid>, State(state): State<AppState>) -> Response {
let entity_id: Uuid = entity_id; // useless obv, it's just to do "something" with entity_id
let the_state: String = state.important; // Same, this is useless, just accessing the state
Html("<html><body><h1>Whatever</h1></body></html>").into_response()
}
async fn post_entity(
Path(entity_id): Path<Uuid>,
Form(form): Form<PlayForm>,
State(state): State<AppState>,
) -> Response {
let entity_id: Uuid = entity_id;
let the_state: String = state.important;
let the_play_string: String = form.play;
Html("<html><body><h1>Whatever</h1></body></html>").into_response()
}
async fn get_index() -> Response {
Html("<html><body><h1>Whatever</h1></body></html>").into_response()
} The resulting compiler seems to be the famous "handlers are of the wrong type" error, but I can't figure out what exactly is wrong. I tried wrapping my state in an Arc, Extracting an Arc, double Arcs as above... but I'm really stuck :) What am I doing wrong? |
@chrisglass try https://docs.rs/axum/latest/axum/attr.debug_handler.html but Edit: and Form must be the last extractor. See https://docs.rs/axum/0.6.0-rc.1/axum/extract/index.html#the-order-of-extractors |
To be clear, the whole state just needs to be clonable if you want to extract it all at once, right? If you only ever extract sub-states, you just need the right |
Ohhh I see, yes, that makes sense. My state didn't derive There's still something fishy with my example relating to the form extractor (state is fixed though!), but that's probably for another issue (or maybe I'll just figure it out myself :) ) Edit: And Form must be the last extractor. OK! Thanks a lot for your help. I'll take a stab at sending some doc touch ups then, to help the next readers :) |
Yes |
Note that this probably is neither a Bug Report or a Feature Request, and just a me-problem. But I got confused by it and @davidpdrsn asked me to file a bug on Reddit. :)
Bug Report
Version
0.6.0-rc.1
Description
I have a small app that has a non-Clone'able state, so I've been using an
Arc
in anExtension
for now. I just poked around with the new State in0.6.0-rc.1
, and foundaxum::routing::Router::with_state_arc
.To me, this function felt like an invitation to pass an Arc to something Unclonable into it:
But that doesn't work. This specific example fails with
and changing the function signature to
State<UnclonableExample>
of course also doesn't work, with a rather cryptic compiler error:The working solution is
and extracting it with
but I wonder if others might be temporarily confused by this as well, and if maybe the documentation can be expanded. Right now, it just says
and it's not really indicating that you're not supposed to use this in an attempt to pass your Arc'ed unclonable state around. But I'm also happy with this being closed without action. 😄
The text was updated successfully, but these errors were encountered: