にっき

技術的な話題はないです

Rust 用のマイクロWebフレームワークを作ってみた

前回 は Hyper 用のルーティングライブラリを作ってみましたが,もう少し手を加えればちょっとしたマイクロフレームワークを作れるのではないと思い至ってしまったので勢いで作ってみました。

github.com

実用には程遠いレベルですが,ある程度フレームワークっぽい程度には実装できたので忘れないうちに内容をまとめておきます。

概要

プロジェクト名は「なんか日本神話っぽい名前のプロジェクト作りたい」という雑な考えで適当につけました。とくにスサノオノミコトへの思い入れがあるわけではないです…

コンセプトとしては,とにかくフレームワーク自体は小さくし,hyperfutures が扱っている領域は可能な限りそれらのクレート自体の機能をそのまま使えるようにというのを意識しています。 今のところ提供している機能は以下の通りです。

  • ルーティング(hyper-router の実装をそのまま移植した)
  • ミドルウェアのサポート

使い方

※ 本記事内のサンプルコードは執筆時(2017-07-07)のバージョンに基づく

基本的なサンプル

単純な例を下に示します。まぁよくあるマイクロフレームワークの書き方と同じ感じですね…

extern crate susanoo;

use susanoo::{Server, Context, AsyncResult};
use susanoo::contrib::futures::{future, Future};
use susanoo::contrib::hyper::{StatusCode, Response, Get};

fn hello(_ctx: Context) -> AsyncResult {
  let response = Response::new()
    .with_status(StatusCode::Ok)
    .with_body("<h1>Hello!</h1>");
  future::ok(response).boxed()
}

fn main() {
  let server = Server::new()
    .with_route(Get, "/", hello);
  server.run("0.0.0.0:4000");
}

ミドルウェアの使用

nickel と同様,ミドルウェアを用いて前段に処理をかませることが可能です。 ミドルウェア自体の実装は今後ちまちま進めていきたいと考えています。

// Authorization ヘッダの検証をするミドルウェア
fn check_auth(mut ctx: Context) -> AsyncResult {
  /* omit */
}

fn index(ctx: Context) -> AsyncResult {
    let user = ctx.map.get::<User>().unwrap();
    future::ok(
        Response::new()
            .with_status(StatusCode::Ok)
            .with_body(format!("<h1>Welcome, {}!</h1>", user.username))
            .into(),
    ).boxed()
}

fn main() {
    let server = Server::new()
        .with_middleware(check_auth)
        .with_route(Get, "/", index);

    server.run("0.0.0.0:4000")
}

その他細かい仕様やサンプルなどはソースコードを参照してください(正直具体的な仕様もまだ確定していないのですが…)

作ってみた感想など

  • フレームワークを作るの自体はすごく簡単だった
    • 主要な機能は hyper / futures / tokio が提供しているものを使えば良い
    • とにかくRustはエコシステムが充実してきており良い
  • 所有権回り,借用チェッカとの闘いが辛い
    • いまだに慣れない…
    • 特に並行処理周りの知識が足りないせいか,雰囲気で型制約を書いてしまっている箇所が多い

おわりに

正直主要なフレームワークiron / nickel / rocket)が futures に対応するまでの話な気もしますが,フレームワークの自作自体は結構面白かったので今後もチマチマとメンテナンスしていけたらなぁと