RustでWebアプリケーション作成 メモ

## ライブラリ宣言

```Rust
#![feature(plugin, decl_macro)]
#![plugin(rocket_codegen)]

extern crate rocket_contrib;
extern crate rocket;
```

## TemplateContext宣言

Templateとは、htmlを抽象化したものです。
TemplateContextとは、Templateの基本骨格のことです。

```Rust
#[derive(Serialize)]
struct TemplateContext {
    name: String,
    items: Vec<String>
}
```

## GET

### indexのGET

`#[get(パス)]`の下に関数で、そのパスにアクセスされた時の挙動を書くことができます。
返り値がRedirectなら他の関数に流すことができます。

```Rust
#[get("/")]
fn index() -> Redirect {
    Redirect::to("/hello/Unknown")
}
```

### 通常のGET

返り値をTemplateにすることで、Templateに変化を適応して出力することができます。

```Rust
#[get("/hello/<name>")]
fn get(name: String) -> Template {
    let context = TemplateContext {
        name: name,
        items: vec!["One".into(), "Two".into(), "Three".into()],
    };
    Template::render("index", &context)
}
```

・Template::render(name, *context)
contextから./templates以下のパスnameからtemplateを生成します。
contextは任意の型で可能ですが、通常、HashMapかstructです。

## 404処理

```Rust
#[catch(404)]
fn not_found(req: &Request) -> Template {
    let mut map = std::collections::HashMap::new();
    map.insert("path", req.uri().as_str());
    Template::render("error/404", &map)
}
```

## ヘルパー関数

リテラルのところを書き換えましょう。
Templateに`{{wow hoge}}`と書くことで、後述の`register_helper`メソッドでヘルパー関数を適応させることができるようになります。

```Rust
type HelperResult = Result<(), RenderError>;

fn wow_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> HelperResult {
    if let Some(param) = h.param(0) {
        write!(rc.writer, "<b><i>{}</i></b>", param.value().render())?;
    }
    Ok(())
}
```

## Rocketアプリケーションの生成

```Rust
fn rocket() -> rocket::Rocket {
    rocket::ignite()
        .mount("/", routes![index, get])
        .catch(catchers![not_found])
        .attach(Template::custom(|engines| {
            engines.handlebars.register_helper("wow", Box::new(wow_helper));
        }))
}
```

・rocket::ignite() -> rocket::Rocket
Rocket.tomlに書いてある設定を適応させたRocketアプリケーションを生成します。
Rocket.tomlについては[こちら](https://github.com/SergioBenitez/Rocket/blob/master/examples/config/Rocket.toml)。

・Rocket.mount(base: &str, routes: Vec<Route>)
baseはベースのパスを、
routesはベースから派生するパスを指定します。
(e.g.)
`mount("/", routes![index, get])`
この例でのindexとgetは、それぞれGET関数のindex関数とget関数です。
routes!マクロでVec<Route>を生成できます。

・Rocket.catch(catchers![not_found])
エラーをcatchします。
not_foundはnot_found関数です。

・Rocket.attach(Template::custom(|engines| {
engines.handlebars.register_helper(ヘルパーセレクター, Box::new(ヘルパー関数)
}))
Rocketアプリケーションに、ヘルパー関数を適応させます。

## main関数

Rocketを走らせます。

```Rust
fn main() {
    rocket().launch();
}
```

## templateの書き方

### String

```html
<h1>Hi {{name}}</h1>
```

### Vec

itemsという変数にVecが入っているとします。

```html
<ul>
  {{#each items}}
     <li>{{this}}</li>
  {{/each}}
</ul>
```

### ヘルパー関数

wowというヘルパートリガーに登録されているヘルパー関数を文字列"this"に適応させる場合です。

```html
<p>Also, check {{ wow "this" }} (custom helper) out!</p>
```

## Rocket.tomlの書き方

作成中です。
[こちら](https://github.com/SergioBenitez/Rocket/blob/master/examples/config/Rocket.toml)も合わせてお読みください。

```:templateディレクトリを指定
[global]
template_dir = "templates"
```

## css等の外部ファイルの読み方

・templates以下にcssディレクトリを配置する。
・cssディレクトリ以下にcssファイルを配置する。（今回はdefault.css）
・外部ファイルオープン用の関数を作成する。

```Rust
use rocket::response::NamedFile;
use std::path::{Path, PathBuf};

#[get("/<path..>")]
fn extern_open(path: PathBuf) -> Option<NamedFile> {
    NamedFile::open(Path::new("templates/").join(path)).ok()
}
```

・外部ファイルオープン用の関数を登録する。

```Rust
fn rocket() -> rocket::Rocket {
    rocket::ignite()
    /* ... */
    .mount("/", routes![index, get, extern_open])
    /* ... */
```