Swan Macro

Swan Macro 是 Swan HTTP 库的过程宏组件,提供声明式的 HTTP 客户端定义语法。
🌟 核心功能
- 声明式客户端定义: 使用宏注解定义 HTTP 客户端和方法
- 自动代码生成: 编译时生成高性能的 HTTP 客户端代码
- 智能重试机制: 方法级渐进式指数退避重试
- 拦截器集成: 无缝集成全局和方法级拦截器
- 动态参数支持: URL 和 header 中的参数占位符
- 状态注入: 类似 Axum 的应用状态管理
📦 安装
将以下内容添加到你的 Cargo.toml:
[dependencies]
swan-macro = "0.1.0"
swan-common = "0.1.0"
serde = { version = "1.0", features = ["derive"] }
anyhow = "1.0"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
🚀 快速开始
基础用法
use serde::{Deserialize, Serialize};
use swan_macro::{http_client, get, post};
#[derive(Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}
#[derive(Serialize)]
struct CreateUserRequest {
name: String,
email: String,
}
#[http_client(base_url = "https://api.example.com")]
struct ApiClient;
impl ApiClient {
#[get(url = "/users/{id}")]
async fn get_user(&self, id: u32) -> anyhow::Result<User> {}
#[post(url = "/users", content_type = json)]
async fn create_user(&self, body: CreateUserRequest) -> anyhow::Result<User> {}
#[get(url = "/users/{id}", retry = "exponential(3, 100ms)")]
async fn get_user_with_retry(&self, id: u32) -> anyhow::Result<User> {}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = ApiClient::new();
let user = client.get_user(1).await?;
println!("用户: {}", user.name);
Ok(())
}
🔧 支持的宏
#[http_client]
定义 HTTP 客户端结构体:
#[http_client(
base_url = "https://api.example.com",
interceptor = MyInterceptor, // 可选:全局拦截器
state = AppState // 可选:应用状态类型
)]
struct ApiClient;
HTTP 方法宏
支持的 HTTP 方法:
#[get(url = "...")] - GET 请求
#[post(url = "...", content_type = json)] - POST 请求
#[put(url = "...", content_type = json)] - PUT 请求
#[delete(url = "...")] - DELETE 请求
方法参数
impl ApiClient {
#[get(
url = "/users/{id}", // 路径参数
header = "Authorization: Bearer {token}", // 动态头部
retry = "exponential(3, 100ms)", // 重试策略
interceptor = MethodLevelInterceptor // 方法级拦截器
)]
async fn get_user(&self, id: u32, token: String) -> anyhow::Result<User> {}
}
🔄 重试机制
重试策略类型
#[get(url = "/api", retry = "exponential(3, 100ms)")]
#[get(url = "/api", retry = "exponential(
max_attempts=5,
base_delay=200ms,
max_delay=30s,
exponential_base=2.0,
jitter_ratio=0.1
)")]
#[get(url = "/api", retry = "fixed(max_attempts=3, delay=1s)")]
自动重试条件
- 5xx 服务器错误 (500-599)
- 429 Too Many Requests (限流)
- 408 Request Timeout (超时)
- 网络连接错误
幂等性保护
默认只对安全的HTTP方法重试:
#[get(url = "/data")] #[put(url = "/data")] #[delete(url = "/data")] #[post(url = "/data")]
#[post(url = "/idempotent", retry = "exponential(
max_attempts=3,
base_delay=100ms,
idempotent_only=false
)")]
🌐 动态参数
URL 参数
#[get(url = "/users/{user_id}/posts/{post_id}")]
async fn get_user_post(&self, user_id: u32, post_id: u32) -> anyhow::Result<Post> {}
#[get(url = "/search?q={query}&page={page}")]
async fn search(&self, query: String, page: u32) -> anyhow::Result<Vec<Post>> {}
#[get(url = "/posts?author={param0}&category={param1}")]
async fn search_by_position(&self, author: String, category: String) -> anyhow::Result<Vec<Post>> {}
动态头部
#[get(
url = "/protected",
header = "Authorization: Bearer {token}",
header = "X-User-ID: {user_id}"
)]
async fn get_protected_data(&self, token: String, user_id: u32) -> anyhow::Result<Data> {}
🔌 拦截器集成
use async_trait::async_trait;
use swan_common::SwanInterceptor;
#[derive(Default)]
struct AuthInterceptor;
#[async_trait]
impl SwanInterceptor for AuthInterceptor {
async fn before_request<'a>(
&self,
request: reqwest::RequestBuilder,
request_body: &'a [u8],
_context: Option<&(dyn std::any::Any + Send + Sync)>,
) -> anyhow::Result<(reqwest::RequestBuilder, std::borrow::Cow<'a, [u8]>)> {
let request = request.header("Authorization", "Bearer token");
Ok((request, std::borrow::Cow::Borrowed(request_body)))
}
async fn after_response(
&self,
response: reqwest::Response,
_context: Option<&(dyn std::any::Any + Send + Sync)>,
) -> anyhow::Result<reqwest::Response> {
println!("响应状态: {}", response.status());
Ok(response)
}
}
#[http_client(base_url = "https://api.example.com", interceptor = AuthInterceptor)]
struct SecureApiClient;
🏷️ 内容类型
支持的内容类型:
content_type = json - application/json
content_type = form_urlencoded - application/x-www-form-urlencoded
content_type = form_multipart - multipart/form-data
⚡ 编译时优化
Swan Macro 在编译时生成高度优化的代码:
- 零运行时开销: 所有配置在编译时确定
- 内联优化: 自动内联小函数调用
- 条件编译: 在 release 模式下移除调试代码
- 智能缓存: 拦截器实例复用
🧪 测试
运行测试:
cargo test --lib
📖 文档
详细的 API 文档:
cargo doc --open
🤝 与 Swan Common 配合使用
Swan Macro 依赖 Swan Common 提供运行时支持:
[dependencies]
swan-macro = "0.1.0"
swan-common = "0.1.0"
📄 许可证
本项目采用 MIT 许可证。详情请查看 LICENSE 文件。