dingtalk-sdk 1.0.6

Dingtalk SDK for Rust.
Documentation

This project is a DingTalk API SDK written in Rust, with async/blocking clients, configurable transport, and typed robot APIs (Webhook + Enterprise).

Features

  • Layered architecture:

    • Public API: Client / BlockingClient + service exports
    • Service layer: api/* (Webhook + Enterprise domain methods)
    • Transport helpers: transport/* (token cache, webhook signature URL, standard API validation)
    • Types layer: types/* (public requests + internal payload models)
    • Auth primitives: auth/* (AppCredentials with redacted debug output)
  • Client architecture:

    • Async: ClientBuilder -> Client -> webhook()/enterprise()
    • Blocking: BlockingClientBuilder -> BlockingClient -> webhook()/enterprise()
  • Builder best-practice options:

    • base URL override (webhook_base_url, enterprise_base_url)
    • transport retry (with_retry / retry_policy, optional non-idempotent retry)
    • default headers (default_header)
    • enterprise access token cache (cache_access_token, token_refresh_margin)
  • Service types:

    • Async: WebhookService, EnterpriseService
    • Blocking: BlockingWebhookService, BlockingEnterpriseService
  • Selectable TLS backend per mode (choose one for each enabled mode):

    • Choosing a TLS feature automatically enables the corresponding runtime mode.
    • Async mode: async-tls-rustls-ring / async-tls-rustls-aws-lc-rs / async-tls-native
    • Blocking mode: blocking-tls-rustls-ring / blocking-tls-rustls-aws-lc-rs / blocking-tls-native
  • Fixed signing backend: hmac + sha2 (HMAC-SHA256 for webhook signature)

  • Compile-time feature guards for invalid combinations.

  • Unified error model: Error, ErrorKind, retry/retry-after helpers.

  • Safe URL construction: normalized base URL + segment-based endpoint building.

Supported Message Types

Webhook Robot

  • Text Messages
  • Link Messages
  • Markdown Messages
  • ActionCard Messages (Single and Multi-Button)
  • FeedCard Messages

Enterprise Robot

  • Group Messages
  • Private (OTO) Messages
  • Automatic message reply handling based on message context
  • Contacts (User/Department Get/List/Create/Update/Delete + lookups)
  • Approvals (Create/Get/List IDs/Terminate)

Installation

Default (async + rustls-ring):

[dependencies]
dingtalk-sdk = "1"

Async only:

[dependencies]
dingtalk-sdk = { version = "1", default-features = false, features = ["async-tls-rustls-ring"] }

Blocking only:

[dependencies]
dingtalk-sdk = { version = "1", default-features = false, features = ["blocking-tls-rustls-ring"] }

Switch TLS backend:

[dependencies]
dingtalk-sdk = { version = "1", default-features = false, features = ["async-tls-rustls-aws-lc-rs"] }

Run Examples

Async webhook:

export DINGTALK_WEBHOOK_TOKEN=your_token
export DINGTALK_WEBHOOK_SECRET=your_secret
cargo run --example async_webhook

Async enterprise contacts:

export DINGTALK_APP_KEY=your_appkey
export DINGTALK_APP_SECRET=your_appsecret
export DINGTALK_ROBOT_CODE=your_robot_code
export DINGTALK_USER_ID=your_userid
cargo run --example async_enterprise_contacts

Blocking examples:

cargo run --no-default-features --features "blocking-tls-rustls-ring" --example blocking_webhook
cargo run --no-default-features --features "blocking-tls-rustls-ring" --example blocking_enterprise_contacts

Quick Examples

Async Client + Webhook Service

use dingtalk_sdk::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::builder().build()?;
    let robot = client.webhook("your_token", Some("your_secret".into()));

    let response = robot
        .send_text_message("Hello from Rust!", None, None, Some(false))
        .await?;
    println!("Sent successfully: {}", response);
    Ok(())
}

Custom endpoint and retry policy:

use std::time::Duration;
use dingtalk_sdk::{Client, RetryPolicy};

let client = Client::builder()
    .webhook_base_url("https://oapi.dingtalk.com")?
    .enterprise_base_url("https://api.dingtalk.com")?
    .retry_policy(RetryPolicy::standard().max_attempts(4))
    .retry_non_idempotent(false)
    .token_refresh_margin(Duration::from_secs(180))
    .build()?;

Async Enterprise Service

use dingtalk_sdk::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::builder().build()?;
    let robot = client.enterprise("appkey", "appsecret", "robot_code");

    let response = robot
        .send_group_message("open_conversation_id", "Greetings", "Hello group from Rust!")
        .await?;
    println!("Message sent: {}", response);

    // Contacts: get user detail
    let user = robot
        .contact_get_user(dingtalk_sdk::ContactGetUserRequest::new("manager123"))
        .await?;
    println!("User: {}", user);

    // Approvals: query instance detail
    let process = robot
        .approval_get_process_instance("PROC-INSTANCE-ID")
        .await?;
    println!("Process: {}", process);
    Ok(())
}

Blocking Client + Webhook Service

use dingtalk_sdk::BlockingClient;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = BlockingClient::builder().build()?;
    let robot = client.webhook("your_token", Some("your_secret".into()));
    let response = robot.send_text_message("Hello from blocking Rust!", None, None, Some(false))?;
    println!("Sent successfully: {}", response);
    Ok(())
}

Tests

Default test suite:

cargo test

Run tests with blocking feature set:

cargo test --no-default-features --features "blocking-tls-rustls-ring"

License

This project is licensed under the MIT License.