Recursive merge of Axum routes with state

I decide to explore full stack web development with rust and decided to use axum
axum have the concept of router
The router builder create router by mapping multiple endpoints and http methods to handlers

Router::new()
    .route("/json", get(validate_json::get_json))
    .route("/validate_json", get(validate_json::validated_json))

The router get generic parameter S that describe the the type of state, a shared object between all handlers, S can be deduced by with_state method which take the shared object

Router::new()
.route("/custom_header", get(custom_middware::read_custom_header)).with_state(some_state)

Router also allow you to merge multiple routers

Router::new()
    .merge(hellowold::hello_router())
    .merge(examples::router())

My problem is how to create router by merging other routers that also merge some routers and so on and at the same time those routers uses the same state (by type and object)

So far I fail to do that because type checks fails

Please provide example

When you ask for help on a compiler error it is important to provide code that can be used to produce the error and also the complete error from running cargo build in the terminal. Otherwise, the person trying to answer will have to try to construct this code themselves, and they'll have to guess to fill in the things you've omitted.

1 Like

Don't want to sound offensive this is specific thing to axum crate. It's not about compile error it's about how this problem is normally solved in axum. I want to attract axum users to show me how they do it.
I can avoid my issue just by implement certain traits or by just not merge routers but that is not satisfying for me. I want wisdom on the topic

All routers you're trying to merge have to have the same type for state.

According to this blog post
Anyway, if you have an example how you do it with multiple routers defined within different modules I will be tankful

The problem is normally solved like this:

  1. If all of your modules use exactly the same state, it will just work. By that I mean, create the routes in the modules, merge them in a central place, and the provide the state for all of them.
  2. If your modules use different states, you can use Router::with_state() within that module to provide the state that is different.

The person who asked you to provide the compiler error is not trying to annoy you. It is genuinely the best way for people here to help you.

You asked for examples. Here you go:

Same state:

use axum::{
    routing::get,
    Router,
};

// define some routes separately
let user_routes = Router::new()
    .route("/users", get(users_list))
    .route("/users/:id", get(users_show));

let team_routes = Router::new()
    .route("/teams", get(teams_list));

// combine them into one
let app = Router::new()
    .merge(user_routes)
    .merge(team_routes);

// could also do `user_routes.merge(team_routes)`

// Our app now accepts
// - GET /users
// - GET /users/:id
// - GET /teams

Different state:

use axum::{
    Router,
    routing::get,
    extract::State,
};

#[derive(Clone)]
struct InnerState {}

#[derive(Clone)]
struct OuterState {}

async fn inner_handler(state: State<InnerState>) {}

let inner_router = Router::new()
    .route("/bar", get(inner_handler))
    .with_state(InnerState {});

async fn outer_handler(state: State<OuterState>) {}

let app = Router::new()
    .route("/", get(outer_handler))
    .merge(inner_router)
    .with_state(OuterState {});

But again, please do reconsider posting the error the compiler gives you and the code that is related to it.

If you absolutely cannot post the error or the code for whatever reason, you can try to isolate the problem my commenting out all of your handlers and then commenting them back in one by one. Once you've found the handler causing the problem, and the cause isn't clear yet, try doing the same with the extractors. This is going to be slow and annoying but perhaps it will clarify the cause and lead you to find a solution.

3 Likes

Thanks for the answer, its not like I hide my super secret implementation, its just tedious to share all the context and all of the cases that the thing works or not works. Also I don't ask for help to understand the errors I get but more of an example how other resolve that kind of issues, maybe link to github repo or something.
So far I discover that if all of the implementation is done in single file and the routers is defined in single chain call/builder its just works but when you decide to split the thing in multiple files it start fall a part. Not sure if it's limitation of the compiler or the implementation but if I need all of my routers to be defined in single function this is not scalable framework, imagine the merge conflicts if several people need to add endpoints in an application.
At that point I decided to start exploring axtix web to see if its more mature as web framework