RustでHTMLテンプレートを使ったWebアプリを作ろう
目次
はじめに
ペルソナ5を全部視聴おわりました。 あのアニメは構図とかセリフがなんというかゲームでしたね。ラスボス戦の感じとか対策RPG感あってとても良かったです。
そして、コードギアスAmazon Primeに入っていたので、見始めました。面白いですね。
テンプレートエンジン
Rustで自前で用意したHTMLを使ったアプリを作っていきましょう。 今回使用するのはこのaskama
クレートの追加
Rustでは、ライブラリとかパッケージのことをクレート(crate)って言うんですね。 厳密にはパッケージの集合がクレートっていう感じみたいですが、そういうようです。
cargo add thiserror
cargo add actix_web
cargo add askama
index.html
Rustからindex.htmlを読み出す
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>App</title>
</head>
<body>
<div>
{% for entry in entries %}
<div>
<div>id: {{ entry.id }}, text: {{ entry.text }}</div>
</div>
{% endfor %}
</div>
</body>
</html>
entriesという構造体の中身を一つずつ取り出すためのfor文はこのように書きます。
{% for entry in entries %}
{% endfor %}
そこの間に、構造体の引数を指定して表示します。
<div>
{% for entry in entries %}
<div>
<div>id: {{ entry.id }}, text: {{ entry.text }}</div>
</div>
{% endfor %}
</div>
Rustコード
HTMLで指定した部分にデータを詰め込みWebAppとして公開するコードを見せる。
コード全文
use actix_web::{get, App, HttpResponse, HttpServer, ResponseError};
use askama::Template;
use thiserror::Error;
struct Contents {
id: u8,
text: String,
}
#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate {
entries: Vec<Contents>,
}
#[derive(Error, Debug)]
enum MyError {
#[error("Failed to render HTML")]
AskamaError(#[from] askama::Error),
}
impl ResponseError for MyError {}
#[get("/")]
async fn index() -> Result<HttpResponse, MyError> {
let mut entries = Vec::new();
entries.push(Contents {
id: 1,
text: "First entry".to_string(),
});
entries.push(Contents {
id: 2,
text: "Second entry".to_string(),
});
let html = IndexTemplate { entries };
let response_body = html.render()?;
Ok(HttpResponse::Ok()
.content_type("text/html")
.body(response_body))
}
#[actix_web::main]
async fn main() -> Result<(), actix_web::Error> {
HttpServer::new(move || App::new().service(index))
.bind("127.0.0.1:1002")?
.run()
.await?;
Ok(())
}
詰め込む構造体はこう書きました。 Vector型に詰め込む準備をします。
struct Contens {
id: u8,
text: String,
}
#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate {
entries: Vec<Contens>,
}
構造体にデータを詰め込みところを書きます。 Vector型に、データをプッシュしていく。
#[get("/")]
async fn index() -> Result<HttpResponse, MyError> {
let mut entries = Vec::new();
entries.push(Contents {
id: 1,
text: "First entry".to_string(),
});
entries.push(Contents {
id: 2,
text: "Second entry".to_string(),
});
let html = IndexTemplate { entries };
let response_body = html.render()?;
Ok(HttpResponse::Ok()
.content_type("text/html")
.body(response_body))
}
実行結果
HTMLに指定した値が出力されましたね。 まずはここまで。
error: template “index.html” not found in directories
道中出くわすであろうエラーについて記載していきます。
--> src\main.rs:10:10
|
10 | #[derive(Template)]
| ^^^^^^^^
|
= note: this error originates in the derive macro `Template` (in Nightly builds, run with
-Z macro-backtrace for more info)
index.htmlを置いたフォルダ名が間違っていたことが原因です。 templatesという名前のフォルダ名で作ってあげると解決します。
まとめ
HTMLで動かすやり方が分かりましたね。 Vue+Rustを動かすようにしたいですね。 ここまで書くとあんまりやってる人が出てこないですからね。