domain-web
actionbook/rust-skills
Build concurrent, type-safe web services with async handlers, middleware, and shared state patterns.
What is domain-web?
A domain-layer skill for Rust web development that enforces constraints around async handlers, thread-safe state management, and request lifecycle. Use when designing REST APIs, GraphQL servers, or WebSocket services with frameworks like axum, actix-web, warp, or rocket.
- Enforce async-first handler design to prevent blocking and latency spikes
- Guide thread-safe shared state patterns using Arc and Arc<RwLock<T>>
- Provide extractor-based request validation and parsing
- Structure error handling via IntoResponse trait implementations
- Compose middleware stacks with Tower layers for cross-cutting concerns
- Map domain constraints to Rust type system and ownership rules
How to install domain-web
npx skills add https://github.com/actionbook/rust-skills --skill domain-webHow to use domain-web
- 1.Identify your web framework (axum, actix-web, warp, or rocket) and review its handler signature
- 2.Structure shared state as Arc<AppState> and pass via State extractor
- 3.Define request types as serde-deserializable structs for type-safe extraction
- 4.Implement IntoResponse for your error type to unify error responses
- 5.Use Tower layers for middleware (logging, auth, CORS, rate limiting)
- 6.Spawn blocking operations with spawn_blocking rather than blocking in handlers
Use cases
- Building a REST API with validated request extractors and unified error responses
- Implementing shared application state (database pools, caches) across concurrent handlers
- Designing middleware chains for authentication, logging, and rate limiting
- Migrating blocking code to async with spawn_blocking for CPU-bound work
- Choosing between axum, actix-web, warp, and rocket based on performance and API style needs
- Backend engineers building HTTP services or APIs
- Rust developers new to async web frameworks
- Teams standardizing on web domain patterns and constraints
domain-web FAQ
Use Arc<T> for immutable state; use Arc<RwLock<T>> only when handlers need to mutate shared data. Prefer immutable patterns and message-passing where possible to avoid lock contention.
Use spawn_blocking for CPU-bound work (compression, hashing) and ensure all I/O is async. Blocking in a handler blocks all tasks on that thread, degrading latency for other requests.
Extractors parse and validate individual request data (State, Json, Path); middleware runs on every request in a stack and handles cross-cutting concerns (logging, auth, CORS).
axum is modern and tower-based; actix-web prioritizes performance; warp emphasizes composable filters; rocket favors rapid development with macros. Match your team's preference and performance needs.
Validate in extractors using type-safe deserialization and custom extractor implementations. This prevents invalid data from reaching handlers and centralizes validation logic.
Full instructions (SKILL.md)
Source of truth, from actionbook/rust-skills.
name: domain-web description: "Use when building web services. Keywords: web server, HTTP, REST API, GraphQL, WebSocket, axum, actix, warp, rocket, tower, hyper, reqwest, middleware, router, handler, extractor, state management, authentication, authorization, JWT, session, cookie, CORS, rate limiting, web 开发, HTTP 服务, API 设计, 中间件, 路由" globs: ["**/Cargo.toml"] user-invocable: false
Web Domain
Layer 3: Domain Constraints
Domain Constraints → Design Implications
| Domain Rule | Design Constraint | Rust Implication |
|---|---|---|
| Stateless HTTP | No request-local globals | State in extractors |
| Concurrency | Handle many connections | Async, Send + Sync |
| Latency SLA | Fast response | Efficient ownership |
| Security | Input validation | Type-safe extractors |
| Observability | Request tracing | tracing + tower layers |
Critical Constraints
Async by Default
RULE: Web handlers must not block
WHY: Block one task = block many requests
RUST: async/await, spawn_blocking for CPU work
State Management
RULE: Shared state must be thread-safe
WHY: Handlers run on any thread
RUST: Arc<T>, Arc<RwLock<T>> for mutable
Request Lifecycle
RULE: Resources live only for request duration
WHY: Memory management, no leaks
RUST: Extractors, proper ownership
Trace Down ↓
From constraints to design (Layer 2):
"Need shared application state"
↓ m07-concurrency: Use Arc for thread-safe sharing
↓ m02-resource: Arc<RwLock<T>> for mutable state
"Need request validation"
↓ m05-type-driven: Validated extractors
↓ m06-error-handling: IntoResponse for errors
"Need middleware stack"
↓ m12-lifecycle: Tower layers
↓ m04-zero-cost: Trait-based composition
Framework Comparison
| Framework | Style | Best For |
|---|---|---|
| axum | Functional, tower | Modern APIs |
| actix-web | Actor-based | High performance |
| warp | Filter composition | Composable APIs |
| rocket | Macro-driven | Rapid development |
Key Crates
| Purpose | Crate |
|---|---|
| HTTP server | axum, actix-web |
| HTTP client | reqwest |
| JSON | serde_json |
| Auth/JWT | jsonwebtoken |
| Session | tower-sessions |
| Database | sqlx, diesel |
| Middleware | tower |
Design Patterns
| Pattern | Purpose | Implementation |
|---|---|---|
| Extractors | Request parsing | State(db), Json(payload) |
| Error response | Unified errors | impl IntoResponse |
| Middleware | Cross-cutting | Tower layers |
| Shared state | App config | Arc<AppState> |
Code Pattern: Axum Handler
async fn handler(
State(db): State<Arc<DbPool>>,
Json(payload): Json<CreateUser>,
) -> Result<Json<User>, AppError> {
let user = db.create_user(&payload).await?;
Ok(Json(user))
}
// Error handling
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match self {
Self::NotFound => (StatusCode::NOT_FOUND, "Not found"),
Self::Internal(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Internal error"),
};
(status, Json(json!({"error": message}))).into_response()
}
}
Common Mistakes
| Mistake | Domain Violation | Fix |
|---|---|---|
| Blocking in handler | Latency spike | spawn_blocking |
| Rc in state | Not Send + Sync | Use Arc |
| No validation | Security risk | Type-safe extractors |
| No error response | Bad UX | IntoResponse impl |
Trace to Layer 1
| Constraint | Layer 2 Pattern | Layer 1 Implementation |
|---|---|---|
| Async handlers | Async/await | tokio runtime |
| Thread-safe state | Shared state | Arc<T>, Arc<RwLock<T>> |
| Request lifecycle | Extractors | Ownership via From<Request> |
| Middleware | Tower layers | Trait-based composition |
Related Skills
| When | See |
|---|---|
| Async patterns | m07-concurrency |
| State management | m02-resource |
| Error handling | m06-error-handling |
| Middleware design | m12-lifecycle |
Related skills
More from actionbook/rust-skills and the wider catalog.

m01-ownership
Diagnose and fix Rust ownership, borrowing, and lifetime errors by understanding data roles and scope boundaries.

m02-resource
Master Rust smart pointers and resource management for correct ownership patterns.

m03-mutability
Resolve Rust mutability conflicts by understanding ownership, borrowing rules, and interior mutability patterns.

m04-zero-cost
Master generics, traits, and zero-cost abstraction—choose static vs. dynamic dispatch correctly.

m05-type-driven
Use Rust's type system to make invalid states unrepresentable at compile time.

m06-error-handling
Master Rust error handling: when to use Result, Option, panic, and how to propagate errors effectively.