Exum
一个轻量级的 Axum 语法糖库,提供更简洁的路由定义语法。
特性
- 🚀 简洁的路由宏语法
- 📦 自动参数提取和类型转换
- 🔧 支持多种HTTP方法
- 🎯 路径参数自动解析
- 📝 查询参数和请求体处理
- ⚡ 省略返回值时默认返回
impl IntoResponse
- 🌍 环境自动检测和配置覆盖
- 🔧 环境变量注入支持
- 📁 多环境配置文件管理
安装
在 Cargo.toml 中添加依赖:
[dependencies]
exum = "0.1.0"
快速开始
use exum::*;
#[get("/hello/:id")]
async fn hello(id: String, #[q] q: String) -> String {
format!("id: {}, query: {}", id, q)
}
#[post("/users")]
async fn create_user(#[b] user: User) -> String {
format!("Created user: {:?}", user)
}
#[get("/simple")]
async fn simple_handler() {
"Hello, World!"
}
#[tokio::main]
async fn main() {
let app = Application::build(ApplicationConfig::default());
app.run().await;
}
路由宏
支持的HTTP方法
#[get(path)] - GET 请求
#[post(path)] - POST 请求
#[put(path)] - PUT 请求
#[delete(path)] - DELETE 请求
#[options(path)] - OPTIONS 请求
#[head(path)] - HEAD 请求
#[trace(path)] - TRACE 请求
#[route(path, method = "METHOD")] - 自定义方法
路径参数
路径参数使用 : 前缀或 {} 语法:
#[get("/users/:id")]
async fn get_user(id: String) -> String {
format!("User ID: {}", id)
}
#[get("/posts/{post_id}/comments/{comment_id}")]
async fn get_comment(post_id: String, comment_id: String) -> String {
format!("Post: {}, Comment: {}", post_id, comment_id)
}
参数提取
查询参数 (#[q])
使用 #[q] 属性自动提取查询参数:
#[get("/search")]
async fn search(#[q] query: String, #[q] page: Option<i32>) -> String {
format!("Search: {}, Page: {:?}", query, page)
}
#[get("/search2")]
async fn search2(#[q] (query, page): (String, Option<i32>)) -> String {
format!("Search: {}, Page: {:?}", query, page)
}
请求体 (#[b])
使用 #[b] 属性处理请求体,支持多种格式:
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
name: String,
age: i32,
}
#[post("/users")]
async fn create_user(#[b] user: User) -> String {
format!("Created user: {:?}", user)
}
#[post("/users/form")]
async fn create_user_form(#[b(form)] user: User) -> String {
format!("Created user from form: {:?}", user)
}
#[post("/users/upload")]
async fn upload_user(#[b(multipart)] user: User) -> String {
format!("Uploaded user: {:?}", user)
}
#[post("/users/optional")]
async fn create_user_optional(#[b] user: Option<User>) -> String {
match user {
Some(u) => format!("Created user: {:?}", u),
None => "No user provided".to_string(),
}
}
配置
手动配置
use exum::config::ApplicationConfig;
let config = ApplicationConfig {
addr: [127, 0, 0, 1],
port: 3000,
};
let app = Application::build(config);
从配置文件加载
创建 config.toml 文件:
addr = [127, 0, 0, 1]
port = 3000
然后在代码中使用:
use exum::config::ApplicationConfig;
let config = ApplicationConfig::from_file("config.toml");
let app = Application::build(config);
环境特定配置
Exum 支持环境特定的配置文件覆盖。系统会自动检测当前环境并加载对应的配置文件:
-
环境检测规则:
- 如果设置了
EXUM_ENV 环境变量,则使用该值
- 否则,在调试模式下使用
dev,生产模式下使用 prod
-
配置文件加载顺序:
- 首先加载
config.toml 作为基础配置
- 然后加载
config.{env}.toml 并覆盖基础配置
示例:
addr = [127, 0, 0, 1]
port = 8080
database_url = "postgres://localhost:5432/mydb"
port = 3000
database_url = "postgres://localhost:5432/mydb_dev"
addr = [0, 0, 0, 0]
database_url = "${DATABASE_URL}"
环境变量注入
配置文件支持环境变量注入,使用 ${VARIABLE_NAME} 语法:
database_url = "${DATABASE_URL}"
api_key = "${API_KEY}"
port = "${PORT:-8080}"
在代码中自动加载配置:
use exum::config::ApplicationConfig;
let config = ApplicationConfig::load();
let app = Application::build(config);
#[main] 宏
Exum 提供了 #[main] 宏来自动注入 Application 的构建和运行代码:
#[main]
async fn main() {
println!("服务器启动中...");
}
#[main(config = "config.toml")]
async fn main() {
println!("使用配置文件启动服务器...");
}
#[main] 宏会自动注入以下代码:
#[tokio::main] 属性
Application::build() 调用
app.run().await 调用
完整示例
use exum::*;
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct CreateUserRequest {
name: String,
email: String,
}
#[get("/users/:id")]
async fn get_user(id: String) -> String {
format!("Getting user with ID: {}", id)
}
#[post("/users")]
async fn create_user(#[b] user: CreateUserRequest) -> String {
format!("Creating user: {:?}", user)
}
#[put("/users/:id")]
async fn update_user(id: String, #[b] user: CreateUserRequest) -> String {
format!("Updating user {}: {:?}", id, user)
}
#[delete("/users/:id")]
async fn delete_user(id: String) -> String {
format!("Deleting user with ID: {}", id)
}
#[get("/search")]
async fn search(#[q] query: String, #[q] page: Option<i32>) -> String {
format!("Searching for '{}' on page {:?}", query, page)
}
#[tokio::main]
async fn main() {
let app = Application::build(ApplicationConfig::default());
app.run().await;
}
Features
deref-app: 为 Application 实现 Deref trait,可以直接访问底层的 Router
full: 包含所有特性
许可证
MIT License