Skip to content

Rustでサーバ処理を追加する#

Rustでは、ハンドラ関数とルーティング機能を使ってWebリクエストを処理します。Actix Webフレームワークを使えば、エンドポイントごとに異なる処理を簡単に実装できます。

WebアプリケーションではURLのパスに紐づけて処理をすることが多いです。

URLとは、サイトを表示するときにブラウザに指定する文字列のことで、例えば https://ukiuni.com/hello のような文字列です。 {通信方式}://{サーバ名}/{パス} のような形式で出来上がっています。

このパスに、処理を紐付けることで、1つのサーバに色々な処理を依頼できるようになっています。

前提#

もし、Rustプロジェクトが手元になければ、こちらの手順でRustプロジェクトを用意してください。こちらでも簡単なハンドラを作成していますが、Rustの重要な処理なので、こちらで改めて説明しています。

ハンドラとルーティングの追加#

src/main.rsに新しいハンドラ関数を追加します。以下のようにファイルを更新してください:

use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use std::time::SystemTime;

#[derive(Serialize)]
struct Message {
    text: String,
}

#[derive(Serialize)]
struct OrderMessage {
    message: String,
    time: String,
}

#[get("/hello")]
async fn hello() -> impl Responder {
    let message = Message {
        text: "こんにちは!".to_string(),
    };
    HttpResponse::Ok().json(message)
}

#[get("/oudon")]
async fn order_oudon() -> impl Responder {
    // 現在時刻を文字列に変換
    let time = SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap()
        .as_secs()
        .to_string();

    let order_message = OrderMessage {
        message: "おうどんください。".to_string(),
        time,
    };

    HttpResponse::Ok().json(order_message)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("サーバーを起動します: http://localhost:8080");
    HttpServer::new(|| {
        App::new()
            .service(hello)
            .service(order_oudon)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

この例では:

  1. OrderMessage 構造体を定義しています。これはJSON形式で応答するためのデータ構造です。
  2. /oudon パスに対応する order_oudon 関数を定義しています。
  3. メイン関数内で App::new() にこのハンドラを登録しています。

注意点: - Rustでは、#[get("/oudon")] のようなアトリビュートを使ってルートを定義します。 - impl Responder を返すことで、ActixがHTTPレスポンスに変換できることを示します。 - .service() メソッドで各エンドポイントをアプリケーションに追加します。

パラメータを受け取るハンドラの追加#

URLパスやクエリパラメータを受け取るハンドラも簡単に実装できます。以下の例を見てみましょう:

use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct GreetQuery {
    name: Option<String>,
}

#[derive(Serialize)]
struct GreetingResponse {
    message: String,
}

#[get("/greet")]
async fn greet(query: web::Query<GreetQuery>) -> impl Responder {
    let name = query.name.as_deref().unwrap_or("ゲスト");

    let response = GreetingResponse {
        message: format!("こんにちは、{}さん!", name),
    };

    HttpResponse::Ok().json(response)
}

// main関数内に以下を追加
// .service(greet)

この例を main.rs に追加してみましょう。main 関数内の App::new().service(greet) を追加するのを忘れないでください:

App::new()
    .service(hello)
    .service(order_oudon)
    .service(greet)

サーバーを起動すると、http://localhost:8080/greet?name=田中 のようなURLでアクセスできるようになります。

HTTPメソッドの指定#

Actixでは、様々なHTTPメソッド(GET, POST, PUT, DELETE など)に対応するマクロが用意されています:

#[get("/resource")] // GETリクエスト
#[post("/resource")] // POSTリクエスト
#[put("/resource")] // PUTリクエスト
#[delete("/resource")] // DELETEリクエスト

例えば、POSTリクエストでJSONデータを受け取る例は以下のようになります:

#[derive(Deserialize)]
struct CreateUser {
    username: String,
    email: String,
}

#[post("/users")]
async fn create_user(user: web::Json<CreateUser>) -> impl Responder {
    // userデータを処理...
    HttpResponse::Created().json(format!("ユーザー {} が作成されました", user.username))
}

// main関数内に以下を追加
// .service(create_user)

これで、Rustでのサーバー処理の基本が完成しました。サーバを起動してみましょう:

cargo run

ブラウザで以下のURLにアクセスしてみてください: - http://localhost:8080/hello - http://localhost:8080/oudon - http://localhost:8080/greet?name=あなたの名前

適切なJSONレスポンスが表示されれば成功です!

次は、Rustでデータベースを扱ってみましょう。