[Rust] actix-webを使ってみよう

2020.04.24

What is actix?

actixとは、Rust製のActorフレームワークです。
(Java/Scalaでいうと、Akkaがメジャーですね)
アクター同士が非同期でメッセージをやり取りし、安全に並行処理を行うことができます。

そのactixをベースとしてWeb開発用機能を追加したのが、
軽量・高速なWeb開発フレームワークであるactix-webです。

actix-webで開発されたアプリは、実行ファイルにHTTPサーバーを含んでいるため、
そのまま使うこともできるし、apacheやnginxの後ろに置くこともできます。  

Environment

今回使用した動作環境は以下のとおりです。

  • OS : MacOS X 10.15.1
  • Rust : 1.42.0

※actix-webはRust 1.39以降で動作します

Setup Rust & actix-web

※Rustのインストール方法についてはこちらもご覧ください

ではRustをインストールしてサンプルプロジェクトをつくってみましょう。

まずはrustup(Rustのインストーラ)をインストールします。

% curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

↑のコマンドでインストール後、terminalを再起動したら、問題ないか確認。

% rustup -V                                                                                                                               
rustup 1.21.1 (7832b2ebe 2019-12-20)

Rustが1.39以降でないなら、uddateします。

% rustup update

Rustのバージョンも更新されました。

%rustc --version
rustc 1.42.0 (b8cedc004 2020-03-09)

Cargoを使ってプロジェクトを作成します。

% cargo new actix-sample
Created binary (application) `actix-sample` package

actix-example/Cargo.tomlで依存ライブラリ(actix-webとactix-rt)を設定します。

[package]
name = "actix-sample"
version = "0.1.0"
authors = ["・・・・・"]
edition = "2018"

[dependencies]
actix-web = "2.0"
actix-rt = "1.0"

src/main.rsを編集。3000番ポートでHTTPサーバが起動するようにします。

use actix_web::{web, App, HttpResponse, HttpServer, Responder};

async fn index() -> impl Responder {
    HttpResponse::Ok().body("Hello world!")
}

async fn index2() -> impl Responder {
    HttpResponse::Ok().json("{\"message\":\"Hello world again!\"}")
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(index))
            .route("/again", web::get().to(index2))
    })
    .bind("127.0.0.1:8088")?
    .run()
    .await
}

runコマンドでアプリを起動しましょう。
http://localhosat:3000にアクセスすれば、Hello Worldが表示されます。
http://localhosat:3000/againにアクセスすれば、json形式でレスポンスが返されます。

% cargo run

とてもシンプルなプログラムですが、ソースのポイントをいくつか説明します。

  • index/index2関数

パスと紐付けるためのリクエストハンドラを作成しています。
これはHttpRequestを受け取り(optional)、Responderをimplimentsした非同期関数となります。

  • main関数

Appインスタンスを作成し、パスとリクエストハンドラを登録します。
そしてHttpServerでAppインスタンスを使用し、8088番ポートで起動します。

なお、ここでは、main関数に、actix_rt::mainマクロを記述しています。
(Actixに実行される非同期関数をマークするためのマクロ)
そして、main関数にもasyncをつけます。
※ async/awaitについてはこのへん参照

新しくパスを追加してみましょう。
今度はgetマクロを使ってハンドラを定義します。

・・・
use actix_web::get;

#[get("/macro-path")]
async fn index3() -> impl Responder {
    HttpResponse::Ok().body("response from index3!")
}
・・・

service関数でindex3を追加しましょう。
他のハンドラよりさらにシンプルに追加できました。

・・・
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(index))
            .route("/again", web::get().to(index2))
            .service(index3) // これを追加
    })
    .bind("127.0.0.1:8088")?
    .run()
    .await
}

まとめ

とりあえずactix-webを動かすことはできました。
基本的な解説はここにありますし、
Gihubにはいろいろなactix-webのサンプルプログラムもありますので、
これらを参考にしてみてください。

参考