This readme was generated by AI, specifically Gemini 3 , Forgive me please 🙏
express_rs is a small, simple, and unopinionated web server library for Rust, heavily inspired by the popular Express.js framework for Node.js. It provides an easy-to-use API for defining routes, handling HTTP requests, and sending responses.
- Express-like API: Simple, chainable methods (
.status(200).json(...)) for familiar development. - Routing: Supports defining routes for fundamental HTTP methods (
GET,POST,PUT, etc.). - Dynamic Routes: Define routes with URL parameters (e.g.,
/user/:id). - Query Parameters: Automatic parsing of search/query parameters (e.g.,
/products?max_price=100). - Request Parsing: Automatic parsing of headers and bodies for common types (
JSON,FormData,Text).
Since this is a standalone module, you can integrate the code directly into your project or define it as a local path dependency in your Cargo.toml if it were packaged as a crate.
Start by creating a new Application and defining a route.
use express_rs::express;
fn main() {
let mut app = express::Application::new();
// Define a GET route for the root path
app.get("/" .to_string(), |req, res| {
// Send a simple HTML response
res.status(200).html("<h1>Welcome to Express_rs!</h1>".to_string())
});
// Start the server on port 8080
// This call is blocking
app.listen(8080);
}The .json() helper automatically sets the Content-Type: application/json header.
app.get("/hello" .to_string(), |req , res| {
// Return a 200 OK status with a JSON body
res.status(200).json(r#"{"message":"Hello from express_rs"}"#.to_string())
});You can define dynamic segments in your route path using a colon (:). Use request.get_param(key) to retrieve the value.
app.get("/user/:id" .to_string(), |request, response| {
// The key 'id' corresponds to the dynamic segment in the route
let id = request.get_param("id").unwrap_or_else(|| "unknown".to_string());
// Respond with the ID we received
response
.status(200)
.json(format!(r#"{{"user_id": "{}"}}"# , id));
});Query parameters (e.g., ?sort=price&limit=10) are automatically parsed and can be accessed via request.get_search_param(key).
// Access this route with: /products?max_price=500&category=electronics
app.get("/products" .to_string(), |request, response| {
let max_price = request.get_search_param("max_price")
.unwrap_or_else(|| "N/A".to_string());
let category = request.get_search_param("category")
.unwrap_or_else(|| "All".to_string());
let message = format!(
r#"{{"message": "Filtering products. Max Price: {}, Category: {}"}}"#,
max_price, category
);
response.status(200).json(message);
});The Request struct handles body parsing based on the Content-Type header.
use express_rs::express::{Method, Body}; // Import Body enum
app.post("/users" .to_string(), |request, response| {
match &request.body {
Some(Body::JSON(json_string)) => {
// In a real app, you would deserialize this JSON string
println!("Received JSON: {}", json_string);
response.status(201).json(r#"{"status": "User created"}"#.to_string())
},
Some(Body::FormData(map)) => {
if let Some(username) = map.get("username") {
println!("Received form data for user: {}", username);
response.status(201).json(r#"{"status": "User created from form"}"#.to_string())
} else {
response.status(400).json(r#"{"error": "Missing username"}"#.to_string())
}
},
_ => response.status(400).json(r#"{"error": "Unsupported body type"}"#.to_string()),
}
});| Method | Signature | Description |
|---|---|---|
new() |
fn new() -> Application |
Creates a new application instance. |
listen() |
fn listen(&mut self, port: i32) |
Starts the HTTP server on 127.0.0.1:<port>. Blocking call. |
get() |
fn get(route: String, function: F) |
Registers a handler for the GET method. |
post() |
fn post(route: String, function: F) |
Registers a handler for the POST method. |
put() |
fn put(route: String, function: F) |
Registers a handler for the PUT method. |
patch() |
fn patch(route: String, function: F) |
Registers a handler for the PATCH method. |
delete() |
fn delete(route: String, function: F) |
Registers a handler for the DELETE method. |
| Field/Method | Type | Description |
|---|---|---|
method |
Method |
The HTTP method used (GET, POST, etc.). |
route |
String |
The raw route path (including query string). |
headers |
HashMap<String, String> |
All request headers. |
body |
Option<Body> |
The parsed request body. |
get_param() |
fn get_param(&self, key: &str) -> Option<String> |
Gets a value from a dynamic URL parameter. |
get_search_param() |
fn get_search_param(&self, key: &str) -> Option<String> |
Gets a value from a query parameter. |
Response methods are chainable, allowing for fluent construction of the response.
| Method | Signature | Description |
|---|---|---|
status() |
fn status(self, code: i32) -> Self |
Sets the HTTP status code (e.g., 200, 404, 500). |
html() |
fn html(self, html: String) -> Self |
Sets the body and Content-Type to text/html. |
json() |
fn json(self, json: String) -> Self |
Sets the body and Content-Type to application/json. |