phonograph/phono-server/src/routes/mod.rs

137 lines
5.2 KiB
Rust
Raw Normal View History

//! Hierarchical HTTP routing.
//!
//! Top level module establishes the overall
//! [`axum::Router`], and submodules organize nested subrouters into manageable
//! chunks. Pragmatically, the submodule tree should be kept fairly flat, lest
//! file paths grow exceedingly long. Deeply nested routers may still be
//! implemented, by use of the `super` keyword.
2025-08-13 18:52:37 -07:00
use axum::{
Router,
2025-10-01 22:36:19 -07:00
extract::State,
http::{HeaderValue, header::CACHE_CONTROL},
2025-10-01 22:36:19 -07:00
response::Redirect,
routing::get,
};
use tower::ServiceBuilder;
use tower_http::{
services::{ServeDir, ServeFile},
set_header::SetResponseHeaderLayer,
};
use crate::auth;
use crate::{app::App, settings::Settings};
2025-10-01 22:37:11 -07:00
mod forms;
mod relations_single;
mod workspaces_multi;
mod workspaces_single;
/// Create the root [`Router`] for the application, including nesting according
/// to the `root_path` [`crate::settings::Settings`] value, setting cache
/// headers, setting up static file handling, and defining fallback handlers.
pub(crate) fn new_router(app: App) -> Router<()> {
let root_path = app.settings.root_path.clone();
let router = Router::new()
.route(
"/",
get(
|State(Settings { root_path, .. }): State<Settings>| async move {
Redirect::to(&format!("{root_path}/workspaces/list/"))
},
),
)
.nest("/workspaces", workspaces_multi::new_router())
2025-09-25 14:51:09 -07:00
.nest("/w", workspaces_single::new_router())
2025-10-01 22:37:11 -07:00
.nest("/f", forms::new_router())
.nest("/auth", auth::new_router())
2025-10-01 22:36:19 -07:00
.route("/__dev-healthz", get(|| async move { "ok" }))
.layer(SetResponseHeaderLayer::if_not_present(
CACHE_CONTROL,
HeaderValue::from_static("no-cache"),
))
.nest_service(
"/js_dist",
ServiceBuilder::new()
.layer(SetResponseHeaderLayer::if_not_present(
CACHE_CONTROL,
HeaderValue::from_static(if cfg!(debug_assertions) {
// Disable caching when developing locally.
"no-cache"
} else {
"max-age=120, stale-while-revalidate=86400"
}),
))
.service(
ServeDir::new("js_dist").not_found_service(
ServiceBuilder::new()
.layer(SetResponseHeaderLayer::if_not_present(
CACHE_CONTROL,
HeaderValue::from_static(if cfg!(debug_assertions) {
// Disable caching when developing locally.
"no-cache"
} else {
"max-age=120, stale-while-revalidate=86400"
}),
))
.service(ServeFile::new("static/_404.html")),
),
),
)
.nest_service(
"/css_dist",
ServiceBuilder::new()
.layer(SetResponseHeaderLayer::if_not_present(
CACHE_CONTROL,
HeaderValue::from_static(if cfg!(debug_assertions) {
// Disable caching when developing locally.
"no-cache"
} else {
"max-age=120, stale-while-revalidate=86400"
}),
))
.service(
ServeDir::new("css_dist").not_found_service(
ServiceBuilder::new()
.layer(SetResponseHeaderLayer::if_not_present(
CACHE_CONTROL,
HeaderValue::from_static("no-cache"),
))
.service(ServeFile::new("static/_404.html")),
),
),
)
.fallback_service(
ServiceBuilder::new()
.layer(SetResponseHeaderLayer::if_not_present(
CACHE_CONTROL,
HeaderValue::from_static(if cfg!(debug_assertions) {
// Disable caching when developing locally.
"no-cache"
} else {
"max-age=120, stale-while-revalidate=86400"
}),
))
.service(
ServeDir::new("static").not_found_service(
ServiceBuilder::new()
.layer(SetResponseHeaderLayer::if_not_present(
CACHE_CONTROL,
// Do not allow caching of paths if they return
// a 404 error.
HeaderValue::from_static("no-cache"),
))
.service(ServeFile::new("static/_404.html")),
),
),
)
.with_state(app);
if root_path.is_empty() {
router
} else {
Router::new()
.nest(&root_path, router)
.fallback(|| async move { Redirect::to(&root_path) })
}
}