feishu-sdk 0.1.1

Feishu/Lark SDK for Rust
Documentation

Feishu SDK Rust

Crates.io Documentation License

Notice: This is a community-maintained crate and is not an official Feishu/Lark SDK.

Rust SDK for Feishu/Lark Open Platform API. Provides a complete, type-safe interface to interact with Feishu APIs.

Features

  • Complete API Coverage: 1448+ operations from Feishu Open Platform
  • Token Management: Automatic app_access_token and tenant_access_token handling
  • Event Processing: Event subscription and card callback handling
  • WebSocket Support: Long connection for real-time messaging
  • HTTP Server: Built-in Salvo server for webhook handling
  • Type Safety: Generated operation constants and typed APIs
  • Async/Await: Full async support with tokio runtime
  • Pluggable Components: Customizable cache, logger, serializer, and HTTP client
  • Code Generation: Operation wrappers + typed model stubs from endpoint catalog

Installation

Add to your Cargo.toml:

[dependencies]
feishu-sdk = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Optional Features

[dependencies]
feishu-sdk = { version = "0.1", features = ["server", "websocket"] }
  • server: Enable HTTP server for event handling (Salvo)
  • websocket: Enable WebSocket client for long connections

Quick Start

Basic Usage

use feishu_sdk::core::{Config, FEISHU_BASE_URL};
use feishu_sdk::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Config::builder("app_id", "app_secret")
        .base_url(FEISHU_BASE_URL)
        .build();

    let client = Client::new(config)?;

    // Get chat list
    let resp = client
        .operation("im.v1.chat.list")
        .query_param("page_size", "20")
        .send()
        .await?;

    println!("Status: {}", resp.status);
    println!("Body: {}", String::from_utf8_lossy(&resp.body));

    Ok(())
}

Send Message

use feishu_sdk::core::Config;
use feishu_sdk::Client;

async fn send_message(client: &Client, chat_id: &str) -> Result<(), Box<dyn std::error::Error>> {
    let message = serde_json::json!({
        "receive_id": chat_id,
        "msg_type": "text",
        "content": r#"{"text":"Hello!"}"#
    });

    let resp = client
        .operation("im.v1.messages.create")
        .path_param("receive_id_type", "chat_id")
        .body_json(&message)?
        .send()
        .await?;

    println!("Message sent: {:?}", resp.json_value()?);
    Ok(())
}

Event Handling Server

use feishu_sdk::core::{noop_logger, Config};
use feishu_sdk::event::{EventDispatcher, EventDispatcherConfig};
use feishu_sdk::server::FeishuServer;

#[tokio::main]
async fn main() {
    let event_config = EventDispatcherConfig::new()
        .verification_token("your_token");

    let dispatcher = EventDispatcher::new(event_config, noop_logger());

    // Register event handlers
    dispatcher.on_event("im.message.receive_v1", |event| {
        Box::pin(async move {
            println!("Received message: {:?}", event);
            Ok(None)
        })
    });

    // Start server
    let server = FeishuServer::new(dispatcher).port(8080);
    server.run().await;
}

WebSocket Client

use feishu_sdk::core::noop_logger;
use feishu_sdk::ws::{WebSocketClient, WsConfig};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = WsConfig::new("wss://ws.feishu.cn/...")
        .heartbeat_interval(Duration::from_secs(30))
        .reconnect_delay(Duration::from_secs(5));

    let client = WebSocketClient::new(config, noop_logger()).await?;

    // Check connection status
    if client.is_connected().await {
        println!("Connected to WebSocket");
    }

    Ok(())
}

Configuration

Basic Configuration

use feishu_sdk::core::{Config, LogLevel, FEISHU_BASE_URL, LARK_BASE_URL};
use std::time::Duration;

let config = Config::builder("app_id", "app_secret")
    .base_url(FEISHU_BASE_URL)        // or LARK_BASE_URL for international
    .log_level(LogLevel::Debug)        // Set log level
    .request_timeout(Duration::from_secs(30))  // Request timeout
    .enable_token_cache(true)          // Enable token caching
    .build();

Marketplace App Configuration

let config = Config::builder("app_id", "app_secret")
    .marketplace_app()                 // Enable marketplace mode
    .app_ticket("your_app_ticket")     // Required for marketplace apps
    .build();

Helpdesk Configuration

let config = Config::builder("app_id", "app_secret")
    .helpdesk("helpdesk_id", "helpdesk_token")
    .build();

Client Options

use feishu_sdk::client::{ClientBuilder, with_http_client, with_log_level, with_request_timeout, with_serializer};
use feishu_sdk::core::{Config, LogLevel};

let client = ClientBuilder::new(Config::builder("app_id", "app_secret").build())
    .with(with_log_level(LogLevel::Debug))
    .with(with_request_timeout(Duration::from_secs(60)))
    .with(with_http_client(custom_http_client))
    .with(with_serializer(custom_serializer))
    .build()?;

API Reference

Operation IDs

Operations use the format: {service}.{version}.{resource}.{method}

Examples:

  • im.v1.messages.create - Send message
  • im.v1.chat.list - List chats
  • contact.v3.user.get - Get user info
  • auth.v3.tenant_access_token.internal.post - Get tenant token

Typed API Wrappers

use feishu_sdk::api::all_services;

// Get chat info
let builder = all_services::im::v1::chat::get(&client, "oc_xxx")
    .query_param("user_id_type", "open_id");

// List users
let builder = all_services::contact::v3::user::list(&client)
    .query_param("department_id", "0")
    .query_param("page_size", "50");

Examples

See the examples/ directory:

  • get_token.rs - Get tenant access token
  • send_message.rs - Send a message
  • get_user.rs - Get user information
  • im_v1_message.rs - IM message operations
  • drive_v1_file.rs - Drive file operations
  • calendar_v4.rs - Calendar operations
  • docx_v1.rs - Docx document operations
  • sheets_v3.rs - Sheets operations
  • bitable_v1.rs - Bitable operations
  • approval_v4.rs - Approval operations
  • event_server.rs - Event handling server
  • card_handler.rs - Card callback server
  • websocket_client.rs - WebSocket client
  • full_app.rs - End-to-end app example (client + event + card)

Run examples:

# Set environment variables
export FEISHU_APP_ID=your_app_id
export FEISHU_APP_SECRET=your_app_secret

# Run example
cargo run --example get_token

# Run server example (requires server feature)
cargo run --features server --example event_server

# Run websocket example (requires websocket feature)
cargo run --features websocket --example websocket_client

Documentation

Error Handling

use feishu_sdk::core::Error;

match client.operation("im.v1.messages.create").send().await {
    Ok(resp) => println!("Success: {:?}", resp.json_value()?),
    Err(Error::Api(api_error)) => {
        println!("API Error: code={}, msg={}", api_error.code, api_error.msg);
    }
    Err(Error::RequestTimeout(_)) => println!("Request timed out"),
    Err(e) => println!("Error: {}", e),
}

License

MIT License