I want to create these routes in axum:
/v1/users/:username # String
/v1/users/:user_id # u64
But creating these routes:
Router::new()
.route("/v1/users/:username", get(get_user))
.route("/v1/users/:user_id", get(get_user))
Is not possible due to this error:
thread 'main' panicked at 'Invalid route "/v1/users/:user_id": insertion failed due to conflict with previously registered route: /v1/users/:username'
How can I create the same route which accepts many different URL parameter types?
This doesn't even make sense on a conceptual level. Imagine you receive a request with uri path /v1/users/12345
. How should the 12345
part be interpreted? As a username, or as a numeric id? If you have some internal logic that for example requires that username must start with a letter, then you could do the following:
Add a single route route("/v1/users/:username-or-id", get(get_user))
.
In get_user
handler use Path(String) extractor.
Inside get_user
manually try to parse path segment and use different business logic depending on the result.
For example:
async fn get_user(Path(username_or_id): Path<String>) -> impl IntoResponse {
if let Ok(numeric_id) = username_or_id.parse::<u64>() {
// use `numeric_id: u64`
} else {
let username = username_or_id;
// use `username: String`
}
}
Instead of this you could just have two separate endpoints, which probably will be clearer and harder to misuse.
/v1/users/:username # String
/v1/users/id/:user_id # u64