Actix-web/RocketでREST APIを構築する
Actix-webやRocketなどの最新のRustウェブフレームワークを使い、ルート、リクエスト、レスポンスを扱うRESTful APIを開発します。
「Actix-web/RocketでREST APIを構築する」はCoddyKit上の無料Learn Rust Codingレッスンです。 これはレッスン1/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn Rust Coding学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn Rust Codingコースには全3レッスンが含まれています。
REST APIとは
REST(REpresentational State Transfer)は、ネットワークアプリケーションのアーキテクチャスタイルです。Webサービスがどのように通信すべきかを定めた原則の集合です。
RESTは、ステートレスでキャッシュ可能なWebサービスを構築し、標準的なHTTPメソッドでリソースを操作するためのガイドラインだと考えてください。
- リソース:ユーザー、商品、注文など、名前を付けられるものすべてです。
- URI:リソースを一意に識別する識別子です(例:
/users/123)。 - HTTPメソッド:リソースに対して実行する標準的な操作です(GET、POST、PUT、DELETE)。
WebサービスにRustを使う理由
RustにはWebサービス開発における独自の利点があり、高性能で信頼性の高いAPIを構築するための有力な選択肢です。
- パフォーマンス:Rustのゼロコスト抽象化により、C/C++に匹敵することも多い、非常に効率的なコードを実現できます。
- メモリ安全性:所有権システムが、ヌルポインタ参照やデータ競合などの一般的なバグを防ぎ、より堅牢なサービスにつながります。
- 並行性:Rustのasync/awaitモデルは安全性の保証と組み合わせることで、並行Webサービスを「恐れずに」構築できます。
- 信頼性:強力な型システムとコンパイル時チェックによって、多くのエラーを早期に検出できます。
Actix-webを知る
RustでWebサービスを構築する際は、フレームワークをよく利用します。Actix-webは、Rust向けの強力で実用的、かつ非常に高速なWebフレームワークです。
Actix-webはアクターフレームワークであるActixの上に構築されていますが、Actix-webを効果的に使うためにアクターを理解する必要はありません。非同期処理向けに設計されているため、多数のAPIリクエストを同時に処理するようなI/Oバウンドのタスクに適しています。
Actix-webには、ルーティング、リクエストとレスポンスの処理、ミドルウェアなどのためのツールが用意されており、複雑なAPIの作成を簡単にできます。
プロジェクトのセットアップと依存関係
まず、新しいRustプロジェクトを作成し、必要な依存関係を追加します。フレームワークにはactix-webを、JSONデータのシリアライズとデシリアライズにはserdeを使用します。
最初に、新しいプロジェクトを作成します。
cargo new my_rest_api --bin
次に、Cargo.tomlファイルの[dependencies]セクションに、次の行を追加します。
[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }
最初のActix-webサーバー
最小構成のActix-webサーバーを書いてみましょう。このコードは、ポート8080で受信HTTPリクエストを待ち受ける基本構造を設定します。まだ特定のルートは処理しませんが、基盤となる部分です。
#[actix_web::main]マクロによって、async fn mainをActix-webのランタイムで実行できるようになります。
use actix_web::{App, HttpServer};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Server running at http://127.0.0.1:8080");
HttpServer::new(|| {
// Our application instance, where we'll add routes
App::new()
})
.bind(("127.0.0.1", 8080))? // Bind to an IP address and port
.run() // Start the server
.await // Await its completion
}GETルートの定義
次に、サーバーへ単純なルートを追加しましょう。ルートは、受信したHTTPリクエストのパスとメソッド(GET /helloなど)を、特定のハンドラー関数に対応付けます。
ハンドラー関数hello_worldは、単に文字列を返します。web::get().to()によって、このハンドラーが/helloパスへのGETリクエスト用に登録されます。
use actix_web::{web, App, HttpServer, Responder};
// A handler function that returns a simple string response
async fn hello_world() -> impl Responder {
"Hello, Actix-web!"
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Server running at http://127.0.0.1:8080");
HttpServer::new(|| {
App::new()
// Register our route: GET /hello maps to hello_world()
.route("/hello", web::get().to(hello_world))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}動的ルートのパスパラメーター
APIでは、IDや名前など、URL内の動的な部分を処理する必要がよくあります。Actix-webでは、これらの値を取得するためにパスパラメーターを使用します。
ルートにプレースホルダー(例:/{name})を定義します。ハンドラーでは、web::Path<String>(またはデシリアライズ可能なその他の型)を使って値を取り出します。
use actix_web::{web, App, HttpServer, Responder};
// Handler function with a path parameter 'name'
async fn greet_name(name: web::Path<String>) -> impl Responder {
format!("Hello, {}!", name.into_inner())
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Server running at http://127.0.0.1:8080");
HttpServer::new(|| {
App::new()
// Route with a dynamic path segment for a name
.route("/greet/{name}", web::get().to(greet_name))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}POSTリクエストとJSONの処理
リソースを作成または更新する場合は、POSTまたはPUTリクエストを使用し、多くの場合、リクエストボディにJSON形式でデータを送信します。
Actix-webでは、web::Json<T>を使ってJSONを簡単に処理できます。想定するJSON構造に対応するRustのstructを定義し、serdeのDeserializeをderiveすると、Actix-webが受信したJSONを自動的に構造体へ解析します。
use actix_web::{web, App, HttpServer, Responder};
use serde::{Deserialize, Serialize};
// Define a struct to represent our incoming JSON data
#[derive(Deserialize, Serialize)]
struct User {
username: String,
email: String,
}
// Handler for POST requests that accepts a JSON User object
async fn create_user(user: web::Json<User>) -> impl Responder {
// In a real app, you'd save this user to a database
format!("User created: {} ({})", user.username, user.email)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Server running at http://127.0.0.1:8080");
HttpServer::new(|| {
App::new()
// POST /users expects a JSON body and maps to create_user()
.route("/users", web::post().to(create_user))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}状態を持つ単純なAPIの構築
これまでに学んだことを組み合わせて、ユーザーのリストをメモリ上で管理する小さなAPIを構築しましょう。web::Dataを使って、アプリケーション固有の状態(ユーザーリスト)を複数のハンドラー間で共有します。
std::sync::Mutexを使うことで、複数の同時リクエストからVec<User>へ安全に変更アクセスできるようにします。GET /usersとPOST /usersのエンドポイントを用意します。
use actix_web::{web, App, HttpServer, Responder, HttpResponse};
use serde::{Deserialize, Serialize};
use std::sync::Mutex; // For shared mutable state
// Define a User struct that can be serialized/deserialized and cloned
#[derive(Deserialize, Serialize, Clone)]
struct User {
id: u32,
username: String,
email: String,
}
// Application state to hold our users and track next ID
struct AppState {
users: Mutex<Vec<User>>,
next_id: Mutex<u32>,
}
// Handler to get all users
async fn get_users(data: web::Data<AppState>) -> impl Responder {
let users = data.users.lock().unwrap(); // Acquire a lock
web::Json(users.clone()) // Return users as JSON
}
// Handler to create a new user
async fn create_user(
data: web::Data<AppState>,
new_user: web::Json<User>,
) -> impl Responder {
let mut users = data.users.lock().unwrap();
let mut next_id = data.next_id.lock().unwrap();
let user = User {
id: *next_id,
username: new_user.username.clone(),
email: new_user.email.clone(),
};
users.push(user.clone());
*next_id += 1; // Increment for the next user
HttpResponse::Created().json(user) // Return 201 Created status and user
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Server running at http://127.0.0.1:8080");
// Create shared application state
let app_state = web::Data::new(AppState {
users: Mutex::new(vec![]), // Initialize with an empty user list
next_id: Mutex::new(1), // Start IDs from 1
});
HttpServer::new(move || { // 'move' closure to capture app_state
App::new()
.app_data(app_state.clone()) // Register shared state with the app
.route("/users", web::get().to(get_users))
.route("/users", web::post().to(create_user))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}API概念のクイックチェック
基本的なActix-webサーバーのセットアップと、さまざまなHTTPリクエストの処理方法を学びました。理解度を確認しましょう。
振り返りと次のステップ
よくできました。RustとActix-webでRESTful APIを構築するための第一歩を踏み出しました。
- REST APIの基本と、Rustが適している理由を学びました。
- 基本的なActix-webプロジェクトのセットアップ方法を学びました。
- GETとPOSTのルート定義について扱いました。
- パスパラメーターの取り出し方とJSONペイロードの処理方法を確認しました。
- 最後に、
web::Dataを使ってメモリ上の状態を管理する単純なAPIを構築しました。
次は、データベースとの統合と堅牢なエラー処理についてさらに学び、より強力で本番環境に対応できるWebサービスを構築しましょう。
よくある質問
「Actix-web/RocketでREST APIを構築する」レッスンは無料ですか?
はい。「Actix-web/RocketでREST APIを構築する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn Rust Codingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn Rust Codingコースには全3レッスンが含まれています。
「Actix-web/RocketでREST APIを構築する」で何を学びますか?
Actix-webやRocketなどの最新のRustウェブフレームワークを使い、ルート、リクエスト、レスポンスを扱うRESTful APIを開発します。 ブラウザで直接実行するハンズオンコードでLearn Rust Codingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Learn Rust Codingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLearn Rust Codingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/3です。
「Actix-web/RocketでREST APIを構築する」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLearn Rust Codingレッスンでコードを書いて実行できますか?
はい。すべてのLearn Rust Codingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Actix-web/RocketでREST APIを構築する
- データベース連携(SQLx/Diesel)
- 認証と認可