[Rust]tide0.13.0でHTMLを表示するサンプル

## 変更

### 2020/6/8

tide: 0.10.0にて、静的htmlをレスポンスとして返すメソッドが追加されました。
これに伴い、記事の内容を

* 静的htmlをレスポンスとして返すサンプル
* htmlテンプレートを使ってレスポンスを作成するサンプル

に変更します。

## 注意

~~tideは2020/6/8時点で開発中です。~~
~~プロダクトでの使用はおすすめしません。~~
[tidev0.13.0](https://github.com/http-rs/tide/releases/tag/v0.13.0)で公式リポジトリから注意文が消えました。

## 環境

* OS: Windows10 2004
* Rust: 
    * Toolchain: stable-x86_64-pc-windows-msvc unchanged
    * rustup: 1.22.1
    * rustc:  1.45.2
    * cargo: 1.45.1
* tide: 0.13.0

## サンプル

### 静的htmlファイル

静的なhtmlファイルはBody::from_file("*.html")でhtml用のレスポンスとして読み込まれる。

```rust:static_html
let mut res = tide::Response::new(StatusCode::Ok);
let body = Body::from_file("filename.html").await?;
res.set_body(body);
```

### htmlテンプレートエンジン

(大体のhtmlテンプレートエンジンで文字列型を返すと思うので)
レスポンスのボディーを `Body::from_string()` で作って、メディアタイプをhtmlに変更する。

```rust:template
let mut res = tide::Response::new(StatusCode::Ok);

// generate_html()は自作の関数です。
// htmlテンプレートエンジンからhtmlをString型で返す関数として読み替えてください。
let html_body = generate_html("param").unwrap();
let body = Body::from_string(html_body);
res.set_body(body);

// Body::from_string()だと、レスポンスがプレーンテキストとして認識されるので、
// mime::HTMLを設定しなおさなければならない。
res.set_content_type(mime::HTML);
```

メディアタイプについては、以下を参照
<https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types>


### コード

<details><summary>cargo.toml(折りたたんでいます)</summary><div>

```toml:cargo.toml
# 省略

[dependencies]
tide = "0.13"

# htmlの生成に使用
tinytemplate = "1.1"
serde = "1.0"

[dependencies.async-std]
version = "1.6"
features = ["attributes"]
```
</div></details>

<details><summary>main.rs(折りたたんでいます)</summary><div>

```rust:main.rs
use tide::http::{mime, StatusCode};
use tide::Body;

#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    let mut app = tide::new();

    app.at("/").get(hello);
    app.at("/hello_html").get(hello_html);
    app.at("/html_template/:name").get(hello_html_from_template);
    app.at("/*").get(not_found);
    app.listen("127.0.0.1:8080").await?;
    Ok(())
}

async fn hello(_req: tide::Request<()>) -> Result<String, tide::Error> {
    Ok("hello".to_string())
}

async fn hello_html(_req: tide::Request<()>) -> Result<tide::Response, tide::Error> {
    let mut res = tide::Response::new(StatusCode::Ok);

    // hello.htmlを作成してプロジェクトルートにおいてください。
    // githubからクローンしている場合には、そのままで問題ありません。
    let body = Body::from_file("hello.html").await?;
    res.set_body(body);
    Ok(res)
}

async fn not_found(_req: tide::Request<()>) -> Result<tide::Response, tide::Error> {
    let mut res = tide::Response::new(StatusCode::NotFound);
    let body = Body::from_string("Not Found".to_string());
    res.set_body(body);
    Ok(res)
}

async fn hello_html_from_template(req: tide::Request<()>) -> Result<tide::Response, tide::Error> {
    let mut res = tide::Response::new(StatusCode::Ok);

    // 'tide::Server.at(*/:name)'の形でルーティングしている場合に、:nameの値を取得する
    let name = req.param::<String>("name")?;

    let html_body = generate_html(name).unwrap();
    let body = Body::from_string(html_body);
    res.set_body(body);
    res.set_content_type(mime::HTML);
    Ok(res)
}


// htmlをテンプレートエンジンで生成します。
use serde::Serialize;
use std::error::Error;
use tinytemplate::TinyTemplate;

#[derive(Serialize)]
struct Context {
    name: String,
}

const HTML_TEMPLATE: &'static str = "<!DOCTYPE html>
    <html lang=\"en\">
        <head>
            <meta charset=\"UTF-8\">
            <title>Hello!</title>
        </head>
        <body>
            <h1>Hello!</h1>
            <p>Hi {name} from Rust</p>
        </body>
    </html>";

pub fn generate_html(name: String) -> Result<String, Box<dyn Error>> {
    let mut template = TinyTemplate::new();
    template.add_template("hello_rust_template", HTML_TEMPLATE)?;

    let context = Context { name };

    let rendered = template.render("hello_rust_template", &context)?;
    Ok(rendered)
}
```
</div></details>

[Githubリポジトリ](https://github.com/yusuke-ota/tide_html_server_sample)

## 最後に

Web周りの知識がほとんどないので、間違っているところも多いと思います。
間違っている部分があれば、ご連絡いただけると幸いです。

## 参考文献

[curl コマンド 使い方メモ](https://qiita.com/yasuhiroki/items/a569d3371a66e365316f)
[MDN Web Docs MIME タイプ (IANA メディアタイプ)](https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types)
[Don't Repeat Yourself tide 0.7.0 を試してみる](https://yuk1tyd.hatenablog.com/entry/2020/04/18/171044)
[DOCS.RS tide](https://docs.rs/tide/0.13.0/tide/index.html)