Files

286 lines
7.6 KiB
Markdown

# Feishu SDK Rust
[![Crates.io](https://img.shields.io/crates/v/feishu-sdk.svg)](https://crates.io/crates/feishu-sdk)
[![Documentation](https://docs.rs/feishu-sdk/badge.svg)](https://docs.rs/feishu-sdk)
[![License](https://img.shields.io/crates/l/feishu-sdk.svg)](https://github.com/your-repo/feishu-sdk-rust)
> 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`:
```toml
[dependencies]
feishu-sdk = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```
### Optional Features
```toml
[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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
let config = Config::builder("app_id", "app_secret")
.helpdesk("helpdesk_id", "helpdesk_token")
.build();
```
### Client Options
```rust
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
```rust
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:
```bash
# 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
- Usage guide: [`docs/USAGE.md`](docs/USAGE.md)
- FAQ: [`docs/FAQ.md`](docs/FAQ.md)
- Migration guide: [`docs/MIGRATION.md`](docs/MIGRATION.md)
- Best practices: [`docs/BEST_PRACTICES.md`](docs/BEST_PRACTICES.md)
## Error Handling
```rust
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