.mdc Rust Actix-web web-backend

Actix-web 4 Rust ウェブフレームワークルール

actix-web 4のプロダクション向けルール: 機能別モジュール構造、型安全なエクストラクター、カスタムエラー型、非同期ベストプラクティス、ミドルウェアスタック。

.mdc · 117 lines
# Actix-web 4 Best Practices

Actix-web 4 is the premier choice for high-performance Rust web services. Adhere to these guidelines for clean, scalable, and production-ready code. Always run `cargo fmt` and `cargo clippy` before committing.

## 1. Code Organization

Organize your codebase by feature or domain, not by generic file types.

Good structure:
```
src/
  main.rs
  db.rs          # Database access logic
  routes/        # HTTP route handlers, grouped by resource
  services/      # Business logic layer
  models/        # Data structures and DTOs
```

Bad: Monolithic `main.rs` or `types.rs`/`impl.rs` for everything.

## 2. Application State (`web::Data<T>`)

Use `web::Data<T>` for dependency injection and sharing application-wide state. For mutable state, wrap in `Arc<Mutex<T>>` or `Arc<RwLock<T>>` and initialize *outside* the `HttpServer::new` closure.

```rust
use actix_web::{web, App, HttpServer};
use std::sync::{Arc, Mutex};

struct AppState {
    request_count: Arc<Mutex<usize>>,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let request_count = Arc::new(Mutex::new(0));  // Initialize outside closure

    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(AppState {
                request_count: request_count.clone(),
            }))
            .route("/", web::get().to(index))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}
```

## 3. Type-Safe Extractors

Leverage Actix-web's type-safe extractors (`web::Json`, `web::Path`, `web::Query`).

```rust
async fn create_user(
    path: web::Path<u32>,
    user_info: web::Json<UserInfo>,
) -> impl Responder {
    let user_id = path.into_inner();
    HttpResponse::Created().json(UserResponse { id: user_id, name: user_info.name.clone() })
}
```

## 4. Custom Error Types with `ResponseError`

Define custom error types that implement `ResponseError` for consistent, structured error responses. Use `thiserror` for ergonomic error definition.

```rust
use actix_web::{error::ResponseError, http::StatusCode, HttpResponse};
use derive_more::{Display, Error};

#[derive(Debug, Display, Error)]
pub enum AppError {
    #[display(fmt = "User not found: {}", id)]
    UserNotFound { id: u32, message: String },
    #[display(fmt = "Database error: {}", _0)]
    DbError(#[from] sqlx::Error),
}

impl ResponseError for AppError {
    fn error_response(&self) -> HttpResponse {
        let status = match self {
            AppError::UserNotFound { .. } => StatusCode::NOT_FOUND,
            AppError::DbError(_) => StatusCode::INTERNAL_SERVER_ERROR,
        };
        HttpResponse::build(status).json(self)
    }
}
```

Do not use generic `actix_web::Error` or `panic!` in handlers.

## 5. Middleware Stack

Always include essential middleware for production readiness:

```rust
App::new()
    .wrap(middleware::Logger::default())     // Request logging
    .wrap(middleware::Compress::default())   // Response compression
    .wrap(middleware::NormalizePath::trim()) // Trailing slash handling
    .wrap(Cors::default())                   // CORS
```

## 6. Blocking Operations

Actix-web is asynchronous. Use `web::block` for CPU-bound or blocking I/O operations:

```rust
async fn handle_blocking_request(body: web::Bytes) -> impl Responder {
    let result = web::block(move || blocking_task(body)).await;
    match result {
        Ok(output) => HttpResponse::Ok().body(output),
        Err(_) => HttpResponse::InternalServerError().finish(),
    }
}
```
Share on X

こちらもおすすめ

web-backend カテゴリの他のルール

もっとルールを探す

CLAUDE.md、.cursorrules、AGENTS.md、Image Prompts の全 223 ルールをチェック。