🌙
axumを静的ウェブサイトホストサーバーにするための基本形メモ (Rust)
ウェブサイトのバックエンドはRustで構築したいと思っており、何となくaxumを使いたいと思っていました。ただ、具体的にaxumは一体何を担うのか等よく理解できておらず、公式の"Hello World"のコードで微妙にわかった気がしても、静的ウェブサイトホスティングとしてはどうなのかがわからないままでした。例としても公式のexamples以外にあまり見当たらず、その例も後から見ると色々な内容が載っており親切なのですが、最初の私にとっては逆に最小構成が埋もれておりパッと見では全体像が見えませんでした。ある程度把握するのに若干苦労したので備忘として残しておきます。おまけでWebAPIサーバーの例も載せています。
[axum 0.7.5]
前提
Cargo.toml
[dependencies]
axum = { version = "0.7.5", features = ["http2"] }
tokio = { version = "1.40.0", features = ["full"] }
tower-http = { version ="0.5.2", features = ["fs"] }
dir tree & static files
project/
├── Cargo.toml
├── src/
│ └── main.rs
└── static/
├── index.html
└── css/
└── style.css
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello World</title>
<link rel="stylesheet" href="./css/style.css" type="text/css">
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
style.css
h1 {
color: #f00;
}
静的ファイルホスティング
最小構成
use tower_http::services::ServeDir;
use axum::Router;
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
// set path of contents files directory as service
let serve_dir = ServeDir::new("./static");
// set router path of the service
let app = Router::new().nest_service("/", serve_dir);
// get TCP listener of requests for port 3000
let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
// starting server
axum::serve(listener, app).await.unwrap();
}
ルーティングの注意点
ルーティングパスを変えるとHTML内のリンクパスの記述も変化させる必要があるため注意する。
- 動作しない例
main.rs
Router::new().nest_service("/static", ServeDir::new("./static"))
index.html
<link rel="stylesheet" href="./css/style.css" type="text/css">
- 動作する例
main.rs
Router::new().nest_service("/static", ServeDir::new("./static"))
index.html
<link rel="stylesheet" href="./static/css/style.css" type="text/css">
WebAPIサーバー
最小構成+
use axum::{Router, routing::get, Json};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
// set router path with response handler for GET request as service
let app = Router::new().route("/", get(hello));
// get TCP listener of requests for port 3000
let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
// starting server
axum::serve(listener, app).await.unwrap();
}
// return string as Content-Type: application/json
async fn hello() -> Json<&'static str> {
Json(r#"{"greeting": "Hello World"}"#)
}
axumの個人的な理解
-
tower
が取り扱うのはあるリクエストに対するレスポンスの定義-
Service
トレイトは簡単にはasync fn(Request) -> Result<Response, Error>
らしい
-
-
hyper
はtokio
前提のHTTPのライブラリ-
tokio
のグリーンスレッドを用いたマルチスレッディング処理 - バッファ操作のラッピング
- 新しいコネクションをポートでリッスン 等
-
-
axum
はhyper
とtower
をうまく組み合わせるための枠組み- そのため
use
にtower
が出てくる -
hyper
はaxum
に内臓されているためuse
には出てこない
- そのため
所感
axumを理解していくための基礎知識が得られたと思います。
Discussion