comdirect-rest-api 0.2.1

High-availability Rust client for the comdirect REST API
Documentation
# comdirect-rest-api

High-availability Rust client for the comdirect REST API.

This crate provides:

- Typed API access for `accounts` and `brokerage` endpoints
- Session lifecycle orchestration (`login`, `try_restore`, `shutdown`)
- Automatic token refresh with state and refresh-token callbacks
- Retry and infrastructure helpers for resilient API calls
- Optional web-based interactive TAN flow via the `web` feature

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
comdirect-rest-api = "0.2.0"
```

Enable web login routes when needed:

```toml
[dependencies]
comdirect-rest-api = { version = "0.2.0", features = ["web"] }
```

## Quick Start

### 1. Restore an existing session (recommended for services)

```rust
use comdirect_rest_api::{Session, SessionConfig};

async fn run() -> Result<(), comdirect_rest_api::ComdirectError> {
    let config = SessionConfig::new("client-id", "client-secret", "username", "pin")
        .with_base_url("https://api.comdirect.de")
        .with_request_timeout(std::time::Duration::from_secs(20))
        .with_refresh_buffer(std::time::Duration::from_secs(90));

    let session = Session::from_config(config)?;
    session.try_restore("persisted-refresh-token").await?;

    let balances = session.accounts().get_balances().await?;
    println!("{} accounts", balances.values.len());

    session.shutdown().await;
    Ok(())
}
```

### 2. Interactive login flow

```rust
use comdirect_rest_api::{Session, TanAction};
use std::io::{self, Write};

async fn run() -> Result<(), comdirect_rest_api::ComdirectError> {
    let session = Session::new("client-id", "client-secret", "username", "pin")?;

    session
        .set_refresh_token_callback(|refresh_token| {
            // Persist this token securely and use try_restore() on next startup.
            println!("new refresh token: {refresh_token}");
        })
        .await;

    session
        .login(|challenge| async move {
            println!("challenge {}", challenge.challenge_id);
            println!("Please approve the Push-TAN in the Comdirect app.");
            print!("Press Enter only after you have approved it... ");
            let _ = io::stdout().flush();
            let mut line = String::new();
            let _ = io::stdin().read_line(&mut line);
            TanAction::ConfirmPushTan
        })
        .await?;

    session.shutdown().await;
    Ok(())
}
```

Important: comdirect does not provide a redirect-based completion step for this TAN flow.
Your application callback must wait for an explicit user confirmation signal (for example a
frontend button like "I've allowed it") before returning `TanAction::ConfirmPushTan`.

## API Surface

Top-level modules:

- `session`: auth lifecycle, restore/login flow, refresh worker integration
- `accounts`: typed account endpoints (balances, single balance, transactions)
- `brokerage`: typed brokerage endpoints (depots, positions, instruments)
- `auth`, `types`, `error`: shared auth models, common types, and error handling
- `web` (feature-gated): mounts browser-driven auth routes for TAN workflows

## Optional Web Feature

When `web` is enabled, you can expose login routes with Axum.

- `Session::login_web(...)` mounts default auth routes under `/comdirect`
- `mount_session_login_route(...)` allows custom route mounting
- The callback must still wait for explicit user confirmation before submitting `ConfirmPushTan`

## Development

Run tests for this crate:

```bash
cargo test -p comdirect-rest-api
```

Run with optional web feature tests/build:

```bash
cargo test -p comdirect-rest-api --features web
```

## License

Licensed under either:

- MIT
- Apache-2.0

at your option.