| Crates.io | web-server-abstraction |
| lib.rs | web-server-abstraction |
| version | 1.0.2 |
| created_at | 2025-08-22 02:54:53.536444+00 |
| updated_at | 2025-08-27 00:30:39.691928+00 |
| description | An ergonomic abstraction layer over popular Rust web frameworks |
| homepage | |
| repository | https://github.com/ciresnave/web-server-abstraction |
| max_upload_size | |
| id | 1805836 |
| size | 789,089 |
An ergonomic abstraction layer over popular Rust web frameworks# Use specific framework adapters
let server = WebServer::with_axum_adapter();
let server = WebServer::with_actix_adapter();
let server = WebServer::with_warp_adapter();
let server = WebServer::with_rocket_adapter();
let server = WebServer::with_salvo_adapter();
let server = WebServer::with_poem_adapter();
// Or use the mock adapter for testing let server = WebServer::with_mock_adapter();ou to write web applications once and run them on any supported framework.
:id) and wildcards (*file) support.get(), .post(), .put(), etc. methods| Framework | Feature Flag | Status |
|---|---|---|
| Mock (Testing) | Default | ✅ Complete |
| Axum | axum |
✅ Complete |
| Actix-Web | actix-web |
✅ Complete |
| Warp | warp |
✅ Complete |
| Rocket | rocket |
✅ Complete |
| Salvo | salvo |
✅ Complete |
| Poem | poem |
✅ Complete |
Note: All framework adapters are production-ready and fully tested with their latest versions.
Add this to your Cargo.toml:
[dependencies]
web-server-abstraction = "1.0.2" # Includes Axum support by default
# Or explicitly enable specific framework features
web-server-abstraction = { version = "1.0.2", features = ["axum"] }
# Enable multiple frameworks
web-server-abstraction = { version = "1.0.2", features = ["axum", "rocket", "poem"] }
use web_server_abstraction::{
WebServer, HttpMethod, Response, StatusCode,
middleware::{LoggingMiddleware, CorsMiddleware},
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = WebServer::new()
// Add middleware
.middleware(LoggingMiddleware::new())
.middleware(CorsMiddleware::new().allow_origin("*"))
// Add routes
.route("/", HttpMethod::GET, |_req| async {
Ok(Response::ok().body("Hello, World!"))
})
.route("/health", HttpMethod::GET, |_req| async {
Ok(Response::ok().body("OK"))
})
.route("/users", HttpMethod::POST, |req| async {
// Parse JSON body
let user: serde_json::Value = req.json().await?;
Ok(Response::new(StatusCode::CREATED)
.header("content-type", "application/json")
.body(serde_json::to_string(&user)?))
});
// Bind and run the server
let bound_server = server.bind("127.0.0.1:3000").await?;
println!("Server running on http://127.0.0.1:3000");
bound_server.run().await?;
Ok(())
}
use web_server_abstraction::WebServer;
// Use specific framework adapters
#[cfg(feature = "axum")]
let server = WebServer::with_axum_adapter();
#[cfg(feature = "actix-web")]
let server = WebServer::with_actix_adapter();
#[cfg(feature = "warp")]
let server = WebServer::with_warp_adapter();
// Or use the mock adapter for testing
let server = WebServer::with_mock_adapter();
The crate is built around several key abstractions:
// Core types are standardized across frameworks
pub struct Request { /* ... */ }
pub struct Response { /* ... */ }
pub enum HttpMethod { GET, POST, PUT, DELETE, /* ... */ }
pub struct StatusCode(pub u16);
Built-in middleware includes:
use web_server_abstraction::middleware::*;
let server = WebServer::new()
.middleware(LoggingMiddleware::new().log_bodies(true))
.middleware(CorsMiddleware::new()
.allow_origin("https://example.com")
.allow_methods(vec!["GET".to_string(), "POST".to_string()])
.allow_credentials(true))
.middleware(AuthMiddleware::new()
.with_bearer_tokens(vec!["secret-token".to_string()]))
.middleware(RateLimitMiddleware::new(100, Duration::from_secs(60)))
.middleware(CompressionMiddleware::new().min_size(1024))
.middleware(SecurityHeadersMiddleware::new())
.middleware(MetricsMiddleware::new())
.middleware(CacheMiddleware::new(Duration::from_secs(300)));
http crateEach framework adapter follows this pattern:
// 1. Convert our types to framework types
fn convert_request(req: Request) -> FrameworkRequest;
fn convert_response(resp: FrameworkResponse) -> Response;
// 2. Implement the adapter interface
impl FrameworkAdapter {
pub async fn bind(&mut self, addr: &str) -> Result<()>;
pub async fn run(self) -> Result<()>;
pub fn route(&mut self, path: &str, method: HttpMethod, handler: HandlerFn);
pub fn middleware(&mut self, middleware: Box<dyn Middleware>);
}
The crate includes a mock adapter for easy testing:
#[tokio::test]
async fn test_my_routes() {
use web_server_abstraction::MockAdapter;
let server = WebServer::with_mock_adapter()
.route("/test", HttpMethod::GET, |_| async {
Ok(Response::ok().body("test"))
});
let bound_server = server.bind("127.0.0.1:0").await.unwrap();
// Mock adapter provides testing utilities
// (In practice, you'd make actual HTTP requests)
}
Run tests with:
cargo test
Run examples with:
cargo run --example basic_server
We welcome contributions! Areas where help is needed:
src/adapters/bind, run, route, middlewareCargo.tomlAdapterType enum in core.rsThe crate includes comprehensive benchmarking infrastructure:
use web_server_abstraction::benchmarks::{
PerformanceProfiler, BenchmarkConfig, BenchmarkSuite
};
// Configure and run performance benchmarks
let config = BenchmarkConfig {
duration: Duration::from_secs(30),
concurrent_requests: 100,
warmup_duration: Duration::from_secs(5),
};
let profiler = PerformanceProfiler::new(config);
let results = profiler.benchmark_scenario("load_test").await?;
// Analyze results with statistical metrics
println!("Average response time: {:?}", results.mean());
println!("95th percentile: {:?}", results.percentile(95.0));
println!("Requests per second: {}", results.requests_per_second());
Features include:
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Many Rust crates need to support multiple web frameworks, leading to:
We believe the benefits outweigh these trade-offs for most use cases, especially for libraries and applications that need broad framework compatibility.