actix-web
actix-web copied to clipboard
default service not defaulting to the parent scope
Expected Behavior
When navigating to nonexistent route in a scope, I'd expect to get the nearest default route that is defined.
Current Behavior
Currently, when a scope does not have a default service set up, it will serve the default service set up in the app (or empty 404 if not set up).
Possible Solution
Look for closest definition of default service while "climbing" down the scopes.
Steps to Reproduce
If we setup routes like so:
/ - our root
~default service
/app scope:
/ - root of app scope
~default service for app scope
/deep scope:
/ - root of deep scope
~no default service
If we navigate to /app/something, we'll end up on the app scope's default service.
However, if we go to /app/deep/something, we end up on the topmost default service. (I'd expect to end up on the app scope's default service).
Code
use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(root)
.service(web::scope("/app").configure(app_config))
.default_service(web::route().to(default_not_found))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
fn app_config(cfg: &mut web::ServiceConfig) {
cfg.service(app_hello);
cfg.service(web::scope("/deep").configure(deep_config));
cfg.default_service(web::route().to(app_not_found));
}
fn deep_config(cfg: &mut web::ServiceConfig) {
cfg.service(deep_hello);
}
#[get("/")]
async fn root() -> impl Responder {
HttpResponse::Ok().body("Root /")
}
async fn default_not_found() -> impl Responder {
HttpResponse::NotFound().body("Default 404!")
}
#[get("/")]
async fn app_hello() -> impl Responder {
HttpResponse::Ok().body("this is app/")
}
async fn app_not_found() -> impl Responder {
HttpResponse::NotFound().body("App scope's 404!")
}
#[get("/")]
async fn deep_hello() -> impl Responder {
HttpResponse::Ok().body("this is app/deep/")
}
Context
I encountered this behavior when working on a web shop project, where route something like: /products/something/details-scope/nonexistent, I'd end up with the default response from the server, which had nothing to do with the products...
If this is entirely intended, please just correct me. Otherwise, maybe it would be possible to configure the behavior of the default service resolution in scopes?