3 releases
Uses new Rust 2024
| new 0.9.2 | Mar 9, 2026 |
|---|---|
| 0.9.1 | Mar 9, 2026 |
| 0.9.0 | Mar 9, 2026 |
#344 in HTTP server
145KB
3K
SLoC
Overview
expressjs aims to provide a clean, expressive, and flexible web framework modeled after the ergonomics of Express.js, but with the performance, safety guarantees, and zero-cost abstractions of Rust.
Our goal is simple: no macro magic, no boilerplate, just modular, async-first routing, powerful middleware, and composable handlers.
Features
- Ergonomic Routing: Express-style routing with
.get(),.post(),.all(), etc. - Robust Middleware System: Layered composition via
app.use(...)enabling powerful request pipelines. - Zero-Macro Abstraction: Minimal
AppandRoutertypes without the need for complex procedural macros. - Fast Route Matching: Powered by an efficient radix tree (
matchthem), supporting parameter extraction (/user/:id). - Memory Efficient: Avoids allocations in the hot path. Uses
SmallVecand a global string interner for path and parameter deduplication. - Extensions & State API: Type-safe, per-request parameter access for seamless state sharing across handlers.
- Comprehensive Built-in Middleware:
cors: Cross-Origin Resource Sharing.auth: Basic, Bearer, and JWT authentication flows.rate_limit: IP-based request throttling.logging: Method, path, and elapsed time tracing.security_headers: Secure defaults (HSTS, X-Frame-Options, etc.).static_serve: Streaming optimization & LRU cache for static files.limit_body: Payload size protections to prevent DoS.normalize_path: Clean routing by normalizing trailing slashes.
Getting Started
Add expressjs to your Cargo.toml:
[dependencies]
expressjs = "0.1.0"
Basic Example
use expressjs::prelude::*;
#[tokio::main]
async fn main() {
let mut app = express();
// Built-in middleware
app.use_with("/{*p}", LoggingMiddleware);
// or similarly app.use_global(LoggingMiddleware);
// Simple routing
app.get("/", async |_req, res| {
res.send_text("Hello from expressjs!")
});
// JSON response
app.get("/api/ping", async |_req, res| {
res.send_json(&serde_json::json!({ "status": "ok", "message": "pong" }))
});
// Start server
app.listen(3000, || async {
println!("Server listening on http://localhost:3000");
}).await;
}
Modularity & Routing
Just like Express, you can mount routers to organize your controllers:
use expressjs::router::Router;
let mut app = express();
let mut users_router = Router::default();
users_router.get("/", |_req, res| async { res.send_text("List of users") });
users_router.post("/", |_req, res| async { res.send_text("User created") });
users_router.get("/:id", |_req, res| async { res.send_text("User details") });
app.use_router("/users", users_router);
Security & Middleware
A robust set of middlewares is provided out of the box to help secure and optimize your app. For instance, setting up secure headers and rate limiting:
use expressjs::middleware::{rate_limit::*, security_headers::*};
// Restrict to 100 requests per 15 minutes per IP
app.use_global(RateLimit::new(100, std::time::Duration::from_secs(900)));
// Apply secure HTTP headers
app.use_global(SecurityHeaders::default());
Performance
expressjs is built for speed:
- Routes are resolved natively using a specialized Radix tree.
- Minimal to zero heap allocations on a typical incoming HTTP request due to clever internal optimizations.
- Handlers are represented as lightweight function pointers/closures under a uniform
Handlertrait.
Contributing
We welcome contributions! Whether you're fixing a bug, proposing a new feature, or improving documentation, please feel free to open an issue or a pull request.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
License
Distributed under the MIT License. See LICENSE for more information.
Dependencies
~16–28MB
~465K SLoC