Implement frontend routing and API fallback handling; add dependencies for include_dir and mime_guess
This commit is contained in:
71
apps/api/src/routes/view.rs
Normal file
71
apps/api/src/routes/view.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
use axum::{
|
||||
Router,
|
||||
body::Bytes,
|
||||
extract::Path,
|
||||
http::{StatusCode, header},
|
||||
response::IntoResponse,
|
||||
routing::{MethodRouter, get},
|
||||
};
|
||||
use include_dir::{Dir, include_dir};
|
||||
use mime_guess::from_path;
|
||||
|
||||
static DIST_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../frontend/build/client");
|
||||
const INDEX_HTML_PATH: &str = "index.html";
|
||||
const INDEX_FILE_NOT_FOUND_HTML: &str = r#"
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>404 Not Found</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>404 Not Found</h1>
|
||||
<p>The requested resource was not found on this server. Possibly the frontend build is missing or corrupted.</p>
|
||||
</body>
|
||||
</html>
|
||||
"#;
|
||||
|
||||
pub fn get_view_router() -> Router {
|
||||
Router::new()
|
||||
// Serve the root index.html
|
||||
.route("/", get(root_view_handler))
|
||||
.route(
|
||||
"/{*wildcard}",
|
||||
MethodRouter::new()
|
||||
.get(|Path(path): Path<String>| async move { view_handler(Some(path)).await }),
|
||||
)
|
||||
}
|
||||
|
||||
async fn root_view_handler() -> impl IntoResponse {
|
||||
view_handler(None).await
|
||||
}
|
||||
|
||||
async fn view_handler(path: Option<String>) -> impl IntoResponse {
|
||||
// If path is empty, serve index.html
|
||||
let incoming_path = if let Some(p) = path {
|
||||
p.trim_start_matches('/').to_string()
|
||||
} else {
|
||||
INDEX_HTML_PATH.to_string()
|
||||
};
|
||||
|
||||
let path = match DIST_DIR.get_file(&incoming_path) {
|
||||
Some(_) => incoming_path,
|
||||
None => INDEX_HTML_PATH.to_string(),
|
||||
};
|
||||
|
||||
match DIST_DIR.get_file(&path) {
|
||||
Some(file) => {
|
||||
let mime = from_path(&path).first_or_octet_stream();
|
||||
let body: Bytes = Bytes::copy_from_slice(file.contents());
|
||||
([(header::CONTENT_TYPE, mime.as_ref())], body).into_response()
|
||||
}
|
||||
// This should never happen, but just in case...
|
||||
None => (
|
||||
StatusCode::NOT_FOUND,
|
||||
[(header::CONTENT_TYPE, "text/plain")],
|
||||
Bytes::from(INDEX_FILE_NOT_FOUND_HTML),
|
||||
)
|
||||
.into_response(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user