Embed Static File
Beside the HTML we might want to server some other static content. For example CSS, JavaScript, or even images. We can embed the content that we would like to serve in the Rust source code and we can create a route setting the Content-Type to the proper value.
[package]
name = "embed-static-file"
version = "0.1.0"
edition = "2024"
publish = false
[dependencies]
axum = "0.8.8"
tokio = { version = "1.50.0", features = ["full"] }
[dev-dependencies]
headers = "0.4.1"
http-body-util = "0.1.3"
tower = { version = "0.5.3", features = ["util"] }
Code
use axum::{
Router,
http::header::{self, HeaderMap},
response::{Html, IntoResponse},
routing::get,
};
async fn handle_main_page() -> Html<&'static str> {
Html(
r#"
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/static/css/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Embedded static file</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
"#,
)
}
async fn send_style_css() -> impl IntoResponse {
let css = r#"
h1 {
color: blue;
}
"#;
let mut headers = HeaderMap::new();
headers.insert(header::CONTENT_TYPE, "text/css".parse().unwrap());
(headers, css)
}
fn create_router() -> Router {
Router::new()
.route("/", get(handle_main_page))
.route("/static/css/style.css", get(send_style_css))
}
#[tokio::main]
async fn main() {
let app = create_router();
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
println!("listening on http://{}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}
#[cfg(test)]
mod tests;
Tests
#![allow(unused)]
fn main() {
use axum::{body::Body, http::Request, http::StatusCode};
use http_body_util::BodyExt;
use tower::ServiceExt;
use super::*;
#[tokio::test]
async fn test_main_page() {
let response = create_router()
.oneshot(Request::builder().uri("/").body(Body::empty()).unwrap())
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let content_type = response.headers().get("content-type").unwrap();
assert_eq!(content_type.to_str().unwrap(), "text/html; charset=utf-8");
let body = response.into_body();
let bytes = body.collect().await.unwrap().to_bytes();
let html = String::from_utf8(bytes.to_vec()).unwrap();
assert!(html.contains("<h1>Hello, World!</h1>"));
}
#[tokio::test]
async fn test_css() {
let response = create_router()
.oneshot(
Request::builder()
.uri("/static/css/style.css")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let content_type = response.headers().get("content-type").unwrap();
assert_eq!(content_type.to_str().unwrap(), "text/css");
let body = response.into_body();
let bytes = body.collect().await.unwrap().to_bytes();
let content = String::from_utf8(bytes.to_vec()).unwrap();
let expected = r#"
h1 {
color: blue;
}
"#;
assert_eq!(content, expected);
}
}