Skip to content
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

RouterIntoService not Clone? #2455

Closed
1 task done
bryanburgers opened this issue Dec 28, 2023 · 2 comments · Fixed by #2456
Closed
1 task done

RouterIntoService not Clone? #2455

bryanburgers opened this issue Dec 28, 2023 · 2 comments · Fixed by #2456
Labels
A-axum C-feature-request Category: A feature request, i.e: not implemented / a PR.

Comments

@bryanburgers
Copy link
Contributor

  • I have looked for existing issues (including closed) about this

Bug Report

Version

  • axum 0.7

Description

I'm trying to turn a Router into a Service so I can use it in root_router.nest_service(...).

All of that together means that, while I can write code that does

let sub_router = submod::create_router();

let router = Router::new()
  .nest("/sub", sub_router);

I can not write code that does

let sub_router_service = submod::create_router().into_service();

let router = Router::new()
  .nest_service("/sub", sub_router_service);

This seems like it might be an oversight? It looks to me like RouterIntoService should trivially implement Clone? (It only has a Router in it.)


Why do I want to use .nest_service instead of .nest in the first place? It's because I have a layer on my subrouter, and when I use .nest that layer doesn't get called for non-matching routes.

@davidpdrsn
Copy link
Member

davidpdrsn commented Dec 28, 2023

Sure, implementing Clone for RouterIntoService seems fine but I'm confused as to why you can't just use Router::nest, since you already have a Router.

@davidpdrsn davidpdrsn added C-feature-request Category: A feature request, i.e: not implemented / a PR. A-axum labels Dec 29, 2023
@bryanburgers
Copy link
Contributor Author

why you can't just use Router::nest, since you already have a Router.

The use case here is that in my sub-router, I'm using sub_router.layer(...) to add a non-trivial URL interceptor that handles requests in a particular way. I want that layer to run for all unhandled routes within that sub_router.

If I nest the sub_router directly into the router, the sub_router doesn't intercept those requests. If I nest the sub_router as a service, the sub_router does intercept those requests.

More details: I have to implement a sub-set of https://www.odata.org/ for part of my API. OData does some weird stuff with URLs that doesn't map directly or nicely to using a Router. So I have my own component called odata_router::Router that implements the subset of OData I need.

It looks like we discussed this at #1245. And some code that I wrote at the time to demonstrate something close to what I'm trying to do is here: https://github.com/bryanburgers/axum-nest-repro.

My actual code looks like this:

// odata.rs
pub fn create_router(state: ApiContext) -> Router {
    // Custom component for doing OData routing
    let odata_router = odata_router::Router::new(state.clone())
        // GET /odata/Property('thisistheid')
        .get("Property", get_property)
        // GET /odata/Property?$top=200$filter=...
        .list("Property", list_property)
        // GET /odata/OpenHouse('thisistheid')
        .get("OpenHouse", get_openhouse)
        // GET /odata/OpenHouse?$top=200$filter=...
        .list("OpenHouse", list_openhouse);

    // axum Router
    Router::new()
        // basic route
        .route("/$metadata", get(edmx::get_metadata))
        // handle everything else that we can with the custom router
        .layer(odata_router)
        .with_state(state)
}

async fn get_property(
    odata_router::Id(id): odata_router::Id,
    ReplicationToken(_token): ReplicationToken,
    State(context): State<ApiContext>,
) -> Result<Json<MaskedProperty>, Error> {
    // ...
}
// lib.rs
    let odata_service = reso::create_router(context.clone()).into_service();
    let api_router = api::create_router();

    Router::new()
        .nest("/api", api_router)
        .nest_service("/odata", odata_service)
        .with_state(context)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-axum C-feature-request Category: A feature request, i.e: not implemented / a PR.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants