Contents
Actix Webとは?なぜ学ぶべきか
Rust言語でWebアプリケーションを開発する際、非同期処理を簡単に実装できるActix Webフレームワークは強力な選択肢です。特にパフォーマンスにこだわりたい開発者や、アシンクロニティの恩恵を受けたい新規学習者にとって、導入が比較的容易で柔軟性が高い点が魅力です。
Actix WebはTokioランタイムに基づいて構築されており、非同期処理を効率的に実装できます。また、シンプルなAPIと明快なコード構造により、学習コストを抑えることが可能です。この記事では、そんなActix Webの基本的な使い方をステップバイステップで紹介します。
環境構築とプロジェクト初期化
Rust新規学習者向けに、Actix Webを導入するための手順を解説します。以下では、Cargo.tomlへの依存関係追加と基本的なプロジェクト構造について説明します。
Cargo.tomlへの依存関係追加
Actix Webを使用するには、まずCargo.tomlに以下のように依存関係を追加します。
|
1 2 3 4 |
[dependencies] actix-web = "4.0" serde = { version = "1.0", features = ["derive"] } |
actix-webは主なフレームワーク。serdeはJSONのシリアライズ/デシリアライズに使用します。
基本的なプロジェクト構造
初期化されたプロジェクトでは、src/main.rsに以下のようにコードを記述することで、基本的なWebサーバーが起動できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
use actix_web::{web, App, HttpResponse, HttpServer}; async fn index() -> HttpResponse { HttpResponse::Ok().body("Hello, Actix Web!") } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .route("/", web::get().to(index)) }) .bind("127.0.0.1:8080")? .run() .await } |
このコードでは、GET /リクエストに応じて「Hello, Actix Web!」というレスポンスを返します。
ルーティング設定の基礎
Actix Webでは、ルートとHTTPメソッドに基づいてハンドラ関数を定義できます。以下にGETリクエストとPOSTリクエストの処理方法を紹介します。
GETリクエストハンドラの作成
#[get]属性を使って、指定されたルートへのGETリクエストを処理する関数を定義できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
use actix_web::{web, App, HttpResponse}; async fn get_handler() -> HttpResponse { HttpResponse::Ok().body("これはGETリクエストの応答です") } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .route("/get", web::get().to(get_handler)) }) .bind("127.0.0.1:8080")? .run() .await } |
このコードでは/getにアクセスすると、定義されたメッセージが返されます。
POSTリクエストハンドラとJSON処理
POSTリクエストは#[post]属性で定義し、web::Json<T>を使ってJSONボディをパースできます。以下はユーザー情報を受け取る例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
use actix_web::{web, App, HttpResponse}; use serde::Deserialize; #[derive(Deserialize)] struct User { name: String, email: String, } async fn post_handler(user: web::Json<User>) -> HttpResponse { format!("受信したユーザー情報: {} <{}>", user.name, user.email) .into() } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .route("/post", web::post().to(post_handler)) }) .bind("127.0.0.1:8080")? .run() .await } |
このコードでは、/postにPOSTリクエストを送信するとJSONボディが解析され、ユーザー情報を返します。
リクエストとレスポンスの扱い方
Actix WebではRequest構造体を使ってリクエスト情報(クエリパラメータやヘッダーなど)を取得できます。また、カスタム応答はResponseBuilderで構築します。
クエリパラメータの取得
クエリパラメータはRequest::query()を使って抽出できます。以下はその例です。
|
1 2 3 4 5 6 7 |
use actix_web::{web, App, HttpResponse, HttpRequest}; async fn query_handler(req: &HttpRequest) -> HttpResponse { let name = req.query().get("name").ok_or("名前が指定されていません")?; format!("こんにちは、{}さん!", name).into() } |
この関数では/query?name=太郎とアクセスすると「こんにちは、太郎さん!」という応答が返されます。
セキュリティ対策: XSS防止の注意点
クエリパラメータやユーザー入力値をレスポンスに直接使用する場合、クロスサイトスクリプティング(XSS)への脆弱性がある可能性があります。
HTMLエスケープを行うなど、安全な出力処理を必須とします。
|
1 2 3 4 5 6 7 8 9 10 11 |
use actix_web::http::header::{self, HeaderValue}; use std::fmt::Write; async fn safe_response(name: &str) -> HttpResponse { let escaped_name = html_escape::encode_text(name); let body = format!("こんにちは、{}さん!", escaped_name); HttpResponse::Ok() .content_type("text/html") .body(body) } |
ヘッダーやボディーへのアクセス
ヘッダー情報はRequest::headers()で取得でき、ボディーはweb::Payloadから読み取れます。以下はヘッダーとボディーの取得例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
use actix_web::{web, App, HttpResponse, HttpRequest}; async fn header_and_body(req: &HttpRequest) -> HttpResponse { let content_type = req.headers().get("Content-Type").unwrap_or(&"不明"); let body_str = String::from_utf8_lossy(req.payload().limit(1024)).to_string(); format!( "Content-Type: {}\nボディー内容: {}", content_type, body_str ) .into() } |
このコードでは、リクエストのヘッダーやボディー情報を取得して応答します。
ミドルウェアによる共通処理の実装
ミドルウェアは、ルーティングやハンドラ処理の前後に実行される共通処理です。以下に標準ミドルウェアと自作ミドルウェアの導入例を紹介します。
標準ミドルウェアの導入例
Actix Webには、ログ出力やクロスドメインリクエスト対応(CORS)など、標準で利用可能なミドルウェアが用意されています。以下はログミドルウェアの例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
use actix_web::{web, App, HttpServer}; #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .wrap(actix_web::middleware::Logger::default()) .route("/", web::get().to(|_| HttpResponse::Ok().body("ログが記録されます"))) }) .bind("127.0.0.1:8080")? .run() .await } |
このコードでは、Logger::default()を使用して、リクエストごとにログ出力を行います。
自作ミドルウェアの書き方
自作ミドルウェアは、MiddlewareTraitを実装した構造体で定義できます。以下は簡単な認証チェックの例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
use actix_web::{dev::Service, middleware::Middleware, Error}; use std::future::Future; use std::pin::Pin; pub struct AuthMiddleware; impl<S> Middleware<S> for AuthMiddleware where S: Service, { type Future = Pin<Box<dyn Future<Output = Result<S::Response, Error>> + Send + 'static>>; fn call(&self, req: ServiceRequest, svc: &S) -> Self::Future { let auth_header = req.headers().get("Authorization"); if auth_header.is_none() || auth_header.unwrap() != "Bearer secret_key" { return Box::pin(async move { Err(actix_web::error::ErrorForbidden("認証に失敗しました")) }); } svc.call(req).map(|res| res) } } |
このミドルウェアは、Authorizationヘッダーが「Bearer secret_key」でない場合にアクセスを拒否します。
注意点: MiddlewareTraitはactix_web::dev::Middlewareから導入し、ServiceRequestとServiceResponseを適切にハンドリングする必要があります。トレイトの実装にはcall()関数が必須です。
簡単なAPIの実装例
Actix WebではRESTful APIとして動作する簡易的なCRUD操作を実現できます。以下はユーザー情報を一覧表示し、作成できる簡単なAPIです。
CRUD操作の最小限なモデル
以下のコードは、User構造体とその処理を定義した例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
use actix_web::{web, App, HttpResponse, HttpServer}; use std::collections::HashMap; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] struct User { id: u32, name: String, } async fn list_users() -> HttpResponse { let users = vec![ User { id: 1, name: "太郎".to_string() }, User { id: 2, name: "花子".to_string() }, ]; HttpResponse::Ok().json(users) } async fn create_user(user: web::Json<User>) -> HttpResponse { let new_id = 3; let created_user = User { id: new_id, name: user.name.clone(), }; HttpResponse::Created().json(created_user) } |
エンドポイント間の連携
この処理をルーティングに追加します。以下は/usersと/users/createへのルート設定です。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
#[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .route("/users", web::get().to(list_users)) .route("/users/create", web::post().to(create_user)) }) .bind("127.0.0.1:8080")? .run() .await } |
このコードでは、GET /usersでユーザー一覧を取得し、POST /users/createで新しいユーザーを作成できます。
学習の次のステップ
本記事ではActix Webの基本的な使い方を中心に解説しましたが、実際の開発には公式ドキュメントと併せてコードを実際に書くことが大切です。以下に進むべき学習ステップをまとめます。
学習ステップの整理(テーブルで比較)
| 項目 | 内容 | 補足 |
|---|---|---|
| 公式ドキュメント確認 | Actix Web公式サイトを参照する | 最新情報やAPI仕様が記載されている |
| 複数のHTTPメソッド実装 | GET、POST以外にPUT/DELETEを試す | RESTful API設計に応用可能 |
| セキュリティ対策学習 | CSRF/CORS/XSS対策を確認する | ミドルウェアと組み合わせて導入 |
重要なポイント
エラーハンドリングの補強:
unwrap()やexpect()は非推奨です。代わりに.ok_or(...).flatten()や.and_then()を使って安全な処理を実装してください。セキュリティベストプラクス
ユーザー入力値は常にエスケープ処理を行ってください。actix-web::html_escapeライブラリなどを利用すると良いです。
おすすめの学習方法
- 実際のプロジェクトにActix Webを導入し、エンドポイントを試してみる
- カスタムミドルウェアを作成し、ログやセキュリティチェック機能を実装する
- レスポンス処理でHTMLエスケープを必ず行い、XSSを防ぐ
公式ドキュメントと併用しながら実際にコードを書いてみましょう。実践することで理解が深まりますので、ぜひチャレンジしてください。