I need to figure out 2 things at least so I can finish the task:
I've made an working example of what I think I should build but instead of my custom struct Users
, I'm using integers
struct AppState {
data: Mutex<Vec<u32>>,
}
#[tokio::main]
async fn main() {
let mut vector = vec![1, 2, 3];
let shared_state = Arc::new(AppState { data: Mutex::new(vector) });
let app = Router::new()
.route("/add", get(add_num))
.route("/get", get(get_nums))
.with_state(shared_state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn add_num(State(state): State<Arc<AppState>>) {
let mut x = Arc::clone(&state);
thread::spawn(move || {
let mut vec = x.data.lock().unwrap();
vec.push(318);
let joined_string: String = vec.iter().map(|&x| x.to_string()).collect::<Vec<String>>().join(", ");
println!("{}", joined_string);
});
}
async fn get_nums(State(state): State<Arc<AppState>>) {
let mut x = Arc::clone(&state);
thread::spawn(move || {
let mut vec = x.data.lock().unwrap();
let joined_string: String = vec.iter().map(|&x| x.to_string()).collect::<Vec<String>>().join(", ");
println!("{}", joined_string);
});
}
The problem occurs when I try to do this with a custom struct instead of u32
numbers. When I define my stuct as
#[derive(Debug, Deserialize, Clone)]
pub struct User {
first_name: String,
age: u32
}
and try to add the route to the router with handler where I would pass the User through a JSON in a post request
...
let app = Router::new()
.route("/user", post(add_user))
.with_state(shared_state);
...
async fn add_user(
Json(user): Json<User>,
State(users_state): State<Arc<UsersState>>,
) {
let mut users = Arc::clone(&users_state);
thread::spawn(move || {
let mut vec = users.users.lock().unwrap();
vec.push(user);
});
}
I get this error which I can't figure out
error[E0277]: the trait bound `fn(Json<User>, State<Arc<UsersState>>) -> impl std::future::Future<Output = ()> {add_user}: Handler<_, _>` is not satisfied
--> src/main.rs:29:30
|
29 | .route("/user", post(add_user))
| ---- ^^^^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(Json<User>, State<Arc<UsersState>>) -> impl std::future::Future<Output = ()> {add_user}`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Handler<T, S>`:
<Layered<L, H, T, S> as Handler<T, S>>
<MethodRouter<S> as Handler<(), S>>
note: required by a bound in `post`
--> /home/dmjne/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.4/src/routing/method_routing.rs:389:1
|
389 | top_level_handler_fn!(post, POST);
| ^^^^^^^^^^^^^^^^^^^^^^----^^^^^^^
| | |
| | required by a bound in this function
| required by this bound in `post`
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.
What am I doing wrong here? What am I missing?
The solution that I am trying is based upon Sharing state with handlers from the axum documentation
The error is that the Json
parameter is first and the State
parameter is second. In Axum there can only be one extractor which consumes the request body (FromRequest
in axum terminology) and it must be the last one.
As the compiler is not super good on this sort of errors, Axum provides a debug_handler
attribute which you can set on handlers to try and understand why they're not working.
Also why are you spawning threads from within your handlers? And why are you cloning your Arc despite getting an owned arc and only using it once?