Let's write β

プログラミング中にできたことか、思ったこととか

RustでWebプログラミング No2 ~ Routerをつかって複数ルート~

前回の記事では、非常にシンプルなHelloWorldを表示するだけのサーバーを作成しIronの基礎を紹介しました。

今回はRouterと呼ばれるMiddlewareを利用して複数のURLに対応したサーバーを作成しました。

routerをCargo.tomlに追加

routerを利用するためにCargo.tomlに以下のようrouterをに追加します

[dependencies]

...other dependencies...

router = "*"

Router

コードの完成形は以下の様です:

extern crate iron;
extern crate router;

use iron::prelude::*;
use iron::status;
use iron::modifiers::{Redirect};
use router::{Router, url_for};

fn main() {

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

    fn redirect_handler(req: &mut Request) -> IronResult<Response> {
        let ref top_url = url_for(req, "index", ::std::collections::HashMap::new());
        return Ok(Response::with((status::Found, Redirect(top_url.clone()))))
    }

    fn greet_handler(req: &mut Request) -> IronResult<Response> {
        let ref router = req.extensions.get::<Router>();
        let ref name = router
            .unwrap()
            .find("name")
            .unwrap();
        return Ok(Response::with(
            (status::Ok,
             format!("Hello {}", name).as_str())
        ));
    }
    
    let mut router = Router::new();
    router.get("/", top_handler, "index");
    router.get("/greet/:name", greet_handler, "greeting");
    router.get("/to-top", redirect_handler, "to-top");

    Iron::new(router).http("localhost:3000").unwrap();
    println!("Listen on localhost:3000");
}

細かく見ていきましょう

Router

let mut router = Router::new();
router.get("/", top_handler, "index");
router.get("/greet/:name", greet_handler, "greeting");
router.get("/to-top", redirect_handler, "to-top");

この部分ではRouterを作成し、いくつかのルーティングを登録しています。

.getの部分はHTTPメソッドを意味していて、.post,.put, .deleteのようにその他各種HTTPメソッドに対応しています。 引数はそれぞれ、マッチするURL, その時に呼び出されるハンドラ、ルーティングIDを定義しています。

ルーティングIDはそのルーティングを後から参照する際に利用できる識別子となっています。

URL

URL中では:paramのようにすることで、後からURLの一部を取得することができます。 また、*を使うことでその部分は任意にマッチするようになります。

URLパラメータの取得

    fn greet_handler(req: &mut Request) -> IronResult<Response> {
        let ref router = req.extensions.get::<Router>();
        let ref name = router
            .unwrap()
            .find("name")
            .unwrap();
        return Ok(Response::with(
            (status::Ok,
             format!("Hello {}", name).as_str())
        ));
    }

このハンドラは/greet/:nameというURLにマッチしたときに呼び出されるようになっているハンドラです。 ハンドラ中で

let ref router = req.extensions.get::<Router>();

とすることでRouterを取得しています。extensionsはMiddlewareがリクエストを拡張するのに利用するもので、 今回の場合はRouterは自身をextensionsに保存しています。

ルータを通してURLのパラメータを取得することができます。findメソッドにURLパラメータ名(この場合は"name")を指定すると パラメータがOptionで手に入るので今回の場合は単純にunwrapしています。

url_for

URL to-topは、アクセスするとトップページにリダイレクトされるURLです。

ハンドラは以下のとおりです:

    fn redirect_handler(req: &mut Request) -> IronResult<Response> {
        let ref top_url = url_for(req, "index", ::std::collections::HashMap::new());
        return Ok(Response::with((status::Found, Redirect(top_url.clone()))))
    }

url_forを使うことでルーティングIDに対応するURLを取得することができます。

レスポンスにRedirectを利用することでユーザーをリダイレクトすることができます。

まとめ

今回はRouter Middlewareを利用して複数のルーティングに対応したHTTPサーバーを実装しました。 また、url_forを利用してルーティング登録時に設定したルーティングIDからURLを取得することができます。

次回はテンプレートエンジンを利用してHTMLページの表示をやってみたいと思います。