Don't Repeat Yourself

Don't Repeat Yourself (DRY) is a principle of software development aimed at reducing repetition of all kinds. -- wikipedia

tide 0.8.0 を試してみる

現時点で 0.8.1 まで出てしまっていますので、まとめて触ってみます。

変更の概要はこちらのリリースノートに詳しくまとまっています。0.8.0 でかなり大掛かりなモジュールの構造に対する変更が入っており、もともとドッグフーディングのために使用していたコードベースを 0.7.0→0.8.0 バージョンに上げた際に、いくつかコンパイルエラーになってしまったコードがありました。

まだまだ開発途上なので致し方ないのですが、tide はこういったバージョンアップによって既存のコードベースがコンパイルエラーしてしまうことが多いです。本番環境で利用する際には、こういった点にまだ注意が必要だと思います。

具体的に修正の入ったモジュールは、

  • tide::server サブモジュールの削除
  • tide::middleware サブモジュールの削除

でした。この中に Cookie などが含まれていましたので、使用していた方は変更が必要だった可能性があります。

前回の記事は下記です。

yuk1tyd.hatenablog.com

リリースノートで気になったもの

  • エンドポイントで ? の使用をできるようになった
  • Server-Sent Events をできるようになった
  • 静的ファイルのサービングをできるようになった

エンドポイントで ? の使用をできるようになった

リリースノート以上の解説の必要はないと思うので割愛しますが、エンドポイントの実装時に ? を用いてエラーハンドリングをできるようになりました。

use async_std::{fs, io};
use tide::{Response, StatusCode};

#[async_std::main]
async fn main() -> io::Result<()> {
    let mut app = tide::new();

    app.at("/").get(|_| async move {
        let mut res = Response::new(StatusCode::Ok);
        res.set_body(fs::read("my_file").await?);
        Ok(res)
    });

    app.listen("localhost:8080").await?;
    Ok(())
}

リリースノートのコードをそのまま引っ張ってきてしまいましたが、このように書けるようになりました。? の結果が Error だった場合は、自動的に 500 Internal Server Error が割り当てられます。

Server-Sent Events をできるようになった

Server-Sent Events というのは、サーバーからプッシュ通信を行えるようにする機能です。W3C によって提案されている内容です。HTTP/1.1 のチャンク形式を元にした機能で、チャンクの少しずつ送信するという特徴を利用して、サーバーから任意のタイミングでクライアントにイベントを通知できます。WebSocket と似ていますが、WebSocket とは HTTP を利用するという点で異なります。

送られた内容を、JavaScript の EventSource API にて取得します。詳しい仕様

今回は curl で確認できそうなので、curl で確認してみます。

コードはリリースノートのそのままなのですが…

use tide::sse;

#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    let mut app = tide::new();
    app.at("/sse").get(sse::endpoint(|_req, sender| async move {
        sender.send("fruit", "banana", None).await;
        sender.send("fruit", "apple", None).await;
        Ok(())
    }));

    println!("Server starts");
    app.listen("localhost:8080").await
}

こういった感じで実装し、サーバーを起動したことを確認します。

tide-dog-fooding is 📦 v0.1.0 via 🦀 v1.43.0 took 3m25s 
❯ cargo run
   Compiling tide-dog-fooding v0.1.0 (~/github/yuk1ty/tide-dog-fooding)
    Finished dev [unoptimized + debuginfo] target(s) in 2.86s
     Running `target/debug/tide-dog-fooding`
Server starts

curl を投げてみた結果です。Content-Type が text/event-stream になっていて、ボディも Server-sent Events の形式に沿っていることがわかりました!

❯ curl localhost:8080/sse -i
HTTP/1.1 200 OK
transfer-encoding: chunked
date: Sat, 16 May 2020 06:46:34 GMT
cache-control: no-cache
content-type: text/event-stream

event:fruit
data:banana

event:fruit
data:apple

内部の実装的には、async-sse というクレートをそのまま利用しているようです。async-std 関係のエコシステムがかなり充実してきていますね。

静的ファイルのサービングをできるようになった

掲題の通りですが、静的ファイルを扱えるようになりました。

この修正に伴って、Route#middleware 関数に型引数が追加になり、その型引数 M に Debug を derive しているという条件が追加されました。なので、従来使用していた Middleware の独自実装のすべての構造体に対して、Debug トレイトを継承させる必要が出てきたため注意が必要です。

余談ですが、0.8.0 時点ではディレクトリトラバーサルが可能な状態のようでしたが、0.8.1 でディレクトリトラバーサル対策を行った PR がマージされています。なので、静的ファイルのサービングを行いたい場合は 0.8.0 を利用しないほうがよさそうです。

感想

PR を1つ1つ読むのがおもしろいです。HTTP サーバーフレームワークフルスクラッチした経験はないので、どのように開発が進んでいっているかが追えて楽しいです。引き続き tide の更新情報は追っていきたいです。

ただ、バージョンを上げるたびにわりと毎回破壊的な変更が入っていて、前バージョンまで使っていたコードが動かなくなる、またはコンパイルエラーの潰しこみが必要になります。なので、tide はまだちょっと本番では試せないかなという印象です。