rust
Iron
OriginalWHITEPLUSDay 16

Rustに入門してIron触ってみた。

この記事はWHITEPLUS Advent Calendar 2017 16日目になります。

株式会社ホワイトプラス、エンジニアインターンの @shamisonn です。

業務ではPython,Goを書き、
趣味ではJava,Javascriptを書いているRust初学者が、
RustのWebフレームワークIronを使ってみたログのような記事です。

エンジニアの方々と雑談していたら興味が湧いたのでRust入門してみます :)

目標

Rust言語初心者が、
RustのWebフレームワークであるironを用いて
Get/Postのhttpリクエストを行えるような
サーバーを立ててみる。

チュートリアル

Rustを始めるにあたって以下を読みました。

丁寧に翻訳されていて、
英語に疎い私でもサクサクと読むことができました :D

環境構築

私の環境はMacなのでbrewを使いました。

$ brew install rust
$ rustc --version
rustc 1.22.1

Rustをインストールすると一緒に
パッケージマネージャであるcargoも一緒に入ってくれました。

$ cargo --version
cargo 0.22.0

新規プロジェクト開始していきます。

$ cargo new iron_learning --bin

--binをつけない場合、
ライブラリ作成用のプロジェクトが生成されます。

中身は以下。

$ cd iron_learning
$ tree -a
.
├── .git
│   └──(略)
├── .gitignore
├── Cargo.toml
└── src
    └── main.rs

パッケージのデフォルトの設定はCargo.tomlにかかれています。

$ cat Cargo.toml
[package]
name = "iron_learning"
version = "0.1.0"
authors = ["shamisonn <hoge@mail.com>"]

[dependencies]

authorsには自動的にgitconfigに登録してる情報が入るようです。
モダンですね。

Webフレームワークironのインストール

iron とはRustで書かれた拡張性と並行性に焦点をあてたフレームワークだそうです。

執筆時現在、RustのWebフレームワークの中でも多くのgithubのスターを
獲得しているようですね。(4671個)

インストールにはCargo.tomlに追記を行います。

[package]
name = "iron_learning"
version = "0.1.0"
authors = ["shamisonn <hoge@mail.com>"]

[dependencies]
iron = "0.6.0" # <- 追記

終わりです!
実行する際には

$ cargo run

とすれば勝手にクレート(いわゆるライブラリ)を取ってきて実行してくれます。
簡単ですね。

ironでのhello world

extern crate iron;

use iron::prelude::*;
use iron::status;

fn main() {
    Iron::new(|_: &mut Request| {
        Ok(Response::with((status::Ok, "Hello World!")))
    }).http("localhost:3000").unwrap();
}

公式のexampleにて紹介されていたhello worldです。
localhost:3000にアクセスするとHello World!が返ってきてくれます。

詳しい構造に関してはこちらが参考になりました。
- RustでWebプログラミング No.1 ~ IronのインストールとHello World~ - Let's write β

ルーティング

ironのミドルウェアをとしてrouterが用意されています。
[dependencies]に対して

router = "0.6.0"

と追記します。

これを用いて先程のhello worldを書き換えてみます。

extern crate iron;
extern crate router;

use iron::prelude::*;
use iron::status;
use router::Router;

fn main() {
    let mut router = Router::new();
    router.get("/", hello, "helloworld");

    Iron::new(router).http("localhost:3000").unwrap();

    fn hello(_: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Ok, "Hello World!")))
    }
}

余談ですがrouterの設定部分に別の文法が用意されているようです。
例えば以下のように設定されている場合

let mut router = Router::new();
router.get("/", hello, "helloworld");
router.get("/hoge", fuga, "piyo");
let router = router!(helloworld: get "/" => hello,
                     piyo: get "/hoge" => fuga);

上記は等価のようです。

簡単にGet/Postをしてみる。

routerに対しては、

router.get
router.post
router.put
router.delete

などのMethodが用意されているようです

したがって以下のように実装しました。

extern crate iron;
extern crate router;

use std::io::Read;

use iron::prelude::*;
use iron::status;
use router::Router;

fn main() {
    let mut router = Router::new();
    router.get("/", hello, "hello");
    router.post("/", hello_prefix, "hello_prefix");

    Iron::new(router).http("localhost:3000").unwrap();

    fn hello(_: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Ok, "Hello World!")))
    }

    fn hello_prefix(req: &mut Request) -> IronResult<Response> {
        let mut body = String::new();
        req.body.read_to_string(&mut body)
            .expect("Failed to read line");

        let res = "Hello ".to_string() + &body + &"!".to_string();
        Ok(Response::with((status::Ok, res)))
    }
}

実行結果は以下

$ curl http://localhost:3000/
Hello World!

$ curl -X POST http://localhost:3000/ -d 'Rust'
Hello Rust!

できました〜。

まとめ

非常に親切なドキュメントとパッケージ管理システムのおかげで、
サクッと実装することができました。(といっても非常に簡単なことしかやっていませんが)

Rustの特徴的な部分に関して紹介するまでに至れず、ちょっと残念な気持ちもありますが、
これをきっかけに新しいことにどんどんチャレンジしてみたいと思います。
もっとRustをやりたい!

参考にしたもの