じゃあ、おうちで学べる

本能を呼び覚ますこのコードに、君は抗えるか

RustでWeb Frameworkを使って錆びろ Rocket と Iron

はじめに

愚かな人類共もRustでCLIを作ったりすることには慣れてきたであろう.そうして,そろそろサーバーサイドでもRustを使い始めたいと思う頃であろうか. 僕がそうである.今回はWebのフレームワークについてHello worldぐらいまでやろうと思う(本当に意味ない).言語はあくまで手段らしいのでRailsチュートリアルをした方が給料は上がりそう.

Rocket

Rocket とは

Rocketは、RustのWebフレームワークであり、柔軟性や型の安全性を犠牲にすることなく、高速な Webアプリケーションを簡単に作成できます。

Hello World

file not found for module `montgomery` · Issue #598 · briansmith/ring · GitHub
rustup で現状(2017.12.25)のversionにupdateした後には上記のような問題がある. なので,defaultコンパイラを変更します

rustup default nightly-2017-12-21

src/main.rs

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/hello/<name>/<age>")]
fn hello(name: String, age: u8) -> String {
    format!("Hello, {} year old named {}!", age, name)
}

fn main() {
    rocket::ignite().mount("/", routes![hello]).launch();
}

./Cargo.toml

[package]
name = "rocket_test"
version = "0.1.0"
authors = ["smotouchi <shuya-motouchi@gmo.jp>"]

[dependencies]
rocket="*"
rocket_codegen="*"

実行する.

$cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/rocket_test`
🔧  Configured for development.
    => address: localhost
    => port: 8000
    => log: normal
    => workers: 2
    => secret key: generated
    => limits: forms = 32KiB
    => tls: disabled

client

# これは失敗する
$wget 127.0.0.1:8000/
# 次は成功する
$ wget  wget 127.0.0.1:8000/hello/sam/122
$ cat 122
Hello, 122 year old named sam!

log 出力

🛰  Mounting '/':
    => GET /hello/<name>/<age>
🚀  Rocket has launched from http://localhost:8000
GET /:
    => Error: No matching routes for GET /.
    => Warning: Responding with 404 Not Found catcher.
    => Response succeeded.
GET /hello/sam/122:
    => Matched: GET /hello/<name>/<age>
    => Outcome: Success
    => Response succeeded.
Version
rocket="0.3.5"
rocket_codegen="0.3.5"
$cargo --version
cargo 0.25.0-nightly (930f9d949 2017-12-05)
その他

上記の問題は解決しており(2018.02.13) 最新のコンパイラでも実行可能ですね. [code] $rustc --version rustc 1.25.0-nightly (b8398d947 2018-02-11)) $cargo run Finished dev [unoptimized + debuginfo] target(s) in 93.43 secs Running target/debug/rocket_test 🔧 Configured for development. => address: localhost => port: 8000 => log: normal => workers: 2 => secret key: generated => limits: forms = 32KiB => tls: disabled 🛰 Mounting '/': => GET /hello// 🚀 Rocket has launched from http://localhost:8000 [/code]

Iron

Iron とは

Ironは、複雑で複雑なアプリケーションやRESTful APIを作成するための小さくても堅牢な基盤を提供する、ミドルウェア指向の高速で柔軟なサーバーフレームワークです。ミドルウェアはIronとバンドルされていません。

Hello World

// This example shows how to create a basic router that maps url to different handlers.
// If you're looking for real routing middleware, check https://github.com/iron/router

extern crate iron;

use std::collections::HashMap;

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

struct Router {
    // Routes here are simply matched with the url path.
    routes: HashMap<String, Box<Handler>>
}

impl Router {
    fn new() -> Self {
        Router { routes: HashMap::new() }
    }

    fn add_route<H>(&mut self, path: String, handler: H) where H: Handler {
        self.routes.insert(path, Box::new(handler));
    }
}

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match self.routes.get(&req.url.path().join("/")) {
            Some(handler) => handler.handle(req),
            None => Ok(Response::with(status::NotFound))
        }
    }
}

fn main() {
    let mut router = Router::new();

    router.add_route("hello".to_string(), |_: &mut Request| {
        Ok(Response::with((status::Ok, "Hello world !")))
    });

    router.add_route("hello/again".to_string(), |_: &mut Request| {
       Ok(Response::with((status::Ok, "Hello again !")))
    });

    router.add_route("error".to_string(), |_: &mut Request| {
       Ok(Response::with(status::BadRequest))
    });

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

client

$wget 127.0.0.1:8000/hello
$cat hello
Hello world !
$wget 127.0.0.1:8000/hello/again
$cat again
Hello again !

設定しない限りログは出てこない

Version
"iron"="0.6.0"

さいごに

ベンチマークミドルウェア連携などの検証を全く行っておりません.今後やります.ごめんなさい;)

おまけ

君のIPは

$ curl inet-ip.info

で分かる.

参照

MVCモデルについて - Qiita
docopt - Rust
RustでAPIを叩くCLIツールを作る - Qiita
Rust のコマンドラインオプション解析色々 - にっき