Routing doesn't work for two non-overlapping routes #2332
-
Expected BehaviorI expect the following code two produce two distinct routes: use std::net::SocketAddr;
use actix_web::{web, App, HttpServer, Responder};
#[actix_web::main]
async fn main() {
let address: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let server = HttpServer::new(move || {
App::new().service(
web::scope("/api/v0").service(
web::scope("/collection")
// FIXME: this routing doesn't work.
// NOTE: switching these two routes doesn't work.
.route("/{uuid}", web::get().to(by_uuid))
.route("/user/{user_name}/{unqualified_id}", web::get().to(by_id)),
),
)
})
.bind(address)
.unwrap();
println!("http://{}", address);
server.run().await.unwrap();
}
pub async fn by_uuid(uuid: web::Path<String>) -> impl Responder {
format!("by UUID: {}", uuid)
}
pub async fn by_id(
user_name: web::Path<String>,
unqualified_id: web::Path<String>,
) -> impl Responder {
format!("by id: {}/{}", user_name, unqualified_id)
} Current BehaviorHowever
It seem Actix is routing the request to the uuid route and hitting an error. Steps to Reproduce (for bugs)
Your Environment
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 7 replies
-
So the issue is just closed without any comment? |
Beta Was this translation helpful? Give feedback.
-
Routes are matches in the order they are declared, so you'll always match the {uuid} route in this case. from
|
Beta Was this translation helpful? Give feedback.
-
I am facing the same Issue, If I make my auth_routes at top of all routes, it stop working, App::new()
.wrap(cors)
.app_data(web::Data::new(db_pool.clone()))
.app_data(web::Data::new(redis_client.clone()))
.app_data(web::Data::new(communicator))
.configure(auth_routes)
.configure(users_routes)
.configure(products_routes)
.configure(roles_routes)
.configure(routes_routes)
.configure(user_role_maps_routes)
.configure(role_route_maps_routes)
.configure(user_product_maps_routes)
.configure(areas_routes)
.configure(brand_social_maps_routes)
.configure(brands_routes)
.configure(building_brand_maps_routes)
.configure(building_spaces_routes)
.configure(buildings_routes)
.configure(business_routes)
.configure(cities_routes)
.configure(countries_routes)
.configure(floors_routes)
.configure(ownership_status_routes)
.configure(socials_routes)
.configure(space_types_routes)
.configure(status_routes) this is my auth_controller.rs #[post("/login")]
pub async fn login(
connection: web::Data<PgPool>,
redis_client: web::Data<RedisHandler>,
entity: web::Json<AuthModel>,
) -> Result<impl Responder, actix_web::Error> {
let service = AuthService::new(connection.as_ref().clone(), redis_client.as_ref().clone());
let result = service.login(&entity.into_inner()).await;
Ok(HttpResponse::Ok().json(result))
}
#[post("/user_products")]
pub async fn products(
connection: web::Data<PgPool>,
entity: web::Json<UserProductModel>,
) -> Result<impl Responder, actix_web::Error> {
let result =
ProductsService::get_products(connection.as_ref().clone(), &entity.into_inner().username)
.await;
Ok(HttpResponse::Ok().json(result))
}
#[post("/user_product_claims")]
pub async fn product_claims(
connection: web::Data<PgPool>,
entity: web::Json<UserProductModel>,
) -> Result<impl Responder, actix_web::Error> {
let user_product = entity.into_inner();
let result = ProductsService::get_claims(
connection.as_ref().clone(),
&user_product.username,
&user_product.product,
)
.await;
Ok(HttpResponse::Ok().json(result))
}
pub fn auth_routes(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("/api/auth")
.service(login)
.service(products)
.service(product_claims),
);
} and this is users_controller.rs #[get("")]
pub async fn get_all(connection: web::Data<PgPool>) -> Result<impl Responder, actix_web::Error> {
let entities = UsersService::get_all(connection.as_ref().clone()).await;
Ok(HttpResponse::Ok().json(entities))
}
#[get("/{id}")]
pub async fn get_by_filter(
connection: web::Data<PgPool>,
filter: web::Path<String>,
) -> Result<impl Responder, actix_web::Error> {
let entities = UsersService::get_by_filter(connection.as_ref().clone(), &filter).await;
Ok(HttpResponse::Ok().json(entities))
}
#[post("")]
pub async fn add(
connection: web::Data<PgPool>,
entity: web::Json<Users>,
) -> Result<impl Responder, actix_web::Error> {
let result = UsersService::add(connection.as_ref().clone(), &entity.into_inner()).await;
Ok(HttpResponse::Ok().json(result))
}
#[put("")]
pub async fn update(
connection: web::Data<PgPool>,
entity: web::Json<Users>,
) -> Result<impl Responder, actix_web::Error> {
let result = UsersService::update(connection.as_ref().clone(), &entity.into_inner()).await;
Ok(HttpResponse::Ok().json(result))
}
#[delete("/{id}")]
pub async fn delete(
connection: web::Data<PgPool>,
id: web::Path<String>,
) -> Result<impl Responder, actix_web::Error> {
let result = UsersService::delete(connection.as_ref().clone(), &id).await;
Ok(HttpResponse::Ok().json(result))
}
pub fn users_routes(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("/api/auth/role/users")
.service(get_all)
.service(get_by_filter)
.service(add)
.service(update)
.service(delete),
);
} |
Beta Was this translation helpful? Give feedback.
Routes are matches in the order they are declared, so you'll always match the {uuid} route in this case.
from
web::resource
docs: