artisan 0.10.0

Api RequesT Framework U Like - 你喜欢的 Rust API 请求框架
Documentation

Artisan

Api RequesT Framework U Like - 你喜欢的 Rust API 请求框架

基于洋葱模型的 Rust HTTP 客户端框架,灵感来自 yansongda/artful

特性

  • 🔄 洋葱模型: 请求层层穿透,响应层层返回
  • 🔌 插件化: 每个请求都是一个插件组合,高度灵活可定制
  • 🛡️ 类型安全: Rust 类型系统确保配置和参数的类型安全
  • 高性能: 全局 HTTP Client 单例,共享连接池
  • 📦 零依赖冲突: 仅使用主流稳定依赖

安装

[dependencies]
artisan = "~0.10"

使用 ~ 版本符号确保依赖兼容性,~0.10 表示兼容 0.10.x 的所有版本。

快速开始

初始化框架

use artisan::{Artful, Config};

// 初始化框架配置(可选)
// 首次调用成功返回 true,后续调用返回 false(OnceLock 不支持覆盖)
Artful::config(Config::default());

基础使用

use artisan::{Artful, Plugin, Rocket, flow_ctrl::Next};
use artisan::plugins::{StartPlugin, AddPayloadBodyPlugin, AddRadarPlugin, ParserPlugin};
use async_trait::async_trait;
use std::sync::Arc;
use std::collections::HashMap;
use serde_json::json;

struct MethodUrlPlugin {
    method: reqwest::Method,
    url: String,
}

#[async_trait]
impl Plugin for MethodUrlPlugin {
    async fn assembly(&self, rocket: &mut Rocket, next: Next<'_>) -> artisan::Result<()> {
        rocket.config.method = self.method.clone();
        rocket.config.url = self.url.clone();
        next.call(rocket).await
    }
}

#[tokio::main]
async fn main() -> artisan::Result<()> {
    let params = HashMap::from([
        ("order_id", json!("123")),
        ("amount", json!(100)),
    ]);

    let plugins: Vec<Arc<dyn artisan::Plugin>> = vec![
        Arc::new(StartPlugin),
        Arc::new(MethodUrlPlugin {
            method: reqwest::Method::POST,
            url: "https://api.example.com/orders".to_string(),
        }),
        Arc::new(AddPayloadBodyPlugin),
        Arc::new(AddRadarPlugin),
        Arc::new(ParserPlugin),
    ];

    let result = Artful::artful(params, plugins).await?;
    
    if let artisan::Destination::Json(json) = result {
        println!("Response: {}", json);
    }

    Ok(())
}

使用 Shortcut 快捷方式

use artisan::{Artful, Shortcut, Plugin};
use artisan::plugins::{StartPlugin, AddPayloadBodyPlugin, AddRadarPlugin, ParserPlugin};
use std::sync::Arc;
use std::collections::HashMap;

#[derive(Default)]
struct MyApiShortcut {
    method: reqwest::Method,
    url: String,
}

impl Shortcut for MyApiShortcut {
    fn get_plugins(&self, _params: &HashMap<String, serde_json::Value>) 
        -> Vec<Arc<dyn Plugin>> 
    {
        vec![
            Arc::new(StartPlugin),
            Arc::new(MethodUrlPlugin {
                method: self.method.clone(),
                url: self.url.clone(),
            }),
            Arc::new(AddPayloadBodyPlugin),
            Arc::new(AddRadarPlugin),
            Arc::new(ParserPlugin),
        ]
    }
}

let result = Artful::shortcut::<MyApiShortcut>(HashMap::new()).await?;

自定义插件

use artisan::{Plugin, Rocket, flow_ctrl::Next};
use async_trait::async_trait;

pub struct SignaturePlugin {
    api_key: String,
}

#[async_trait]
impl Plugin for SignaturePlugin {
    async fn assembly(&self, rocket: &mut Rocket, next: Next<'_>) -> artisan::Result<()> {
        rocket.config.headers.insert(
            "X-Signature".to_string(),
            sign(&self.api_key, &rocket.payload),
        );
        
        next.call(rocket).await
    }
}

错误处理: 插件返回 Result<()>,任一插件失败会终止整个链并传播错误。

核心概念

Rocket - 请求载体

Rocket 是整个请求生命周期中的数据载体:

pub struct Rocket {
    params: HashMap<String, Value>,   // 原始参数(不变)
    pub payload: HashMap<String, Value>, // 业务参数(可修改)
    pub config: RocketConfig,         // HTTP 配置(可修改)
    pub radar: Option<Request>,       // HTTP 请求对象
    pub destination: Option<Destination>, // 解析结果
    pub packer: Arc<dyn Packer>,      // 序列化器
}

设计说明

  • params: 原始参数,由调用方传入,整个生命周期中保持不变
  • payload: 业务参数,由 StartPluginparams 初始化,后续插件可修改
  • config: HTTP 配置,包含 direction(响应解析策略),由插件负责设置

RocketConfig - 请求配置

pub struct RocketConfig {
    pub method: reqwest::Method,
    pub url: String,
    pub headers: HashMap<String, String>,
    pub body: Option<String>,
    pub http: HttpOptions,
    pub direction: DirectionKind,     // 响应解析策略
}

Plugin - 插件(洋葱模型)

插件是洋葱模型的核心,每个插件可以在请求前向和后向阶段执行操作:

#[async_trait]
pub trait Plugin: Send + Sync + 'static {
    async fn assembly(&self, rocket: &mut Rocket, next: Next<'_>) -> Result<()>;
}

执行流程:

请求 → Plugin1 前向 → Plugin2 前向 → Plugin3 前向 → HTTP 请求
响应 ← Plugin1 后向 ← Plugin2 后向 ← Plugin3 后向 ← HTTP 响应

Direction - 响应解析策略

pub enum DirectionKind {
    Json,             // 解析为 JSON(默认)
    Response,         // 返回原始 Response
    NoRequest,        // 不发起 HTTP 请求
    Custom(Arc<dyn Direction>), // 自定义解析器
}

内置插件

插件 功能
StartPlugin 将 params 初始化到 payload
AddPayloadBodyPlugin 将 payload 序列化为请求体
AddRadarPlugin 构建 HTTP Request
ParserPlugin 执行请求并解析响应

文档

详细架构设计请参阅 docs/ARCHITECTURE.md

许可证

MIT License