twelve-data-client 0.3.0

Rust API client for Twelve Data with automatic builder pattern generation. Provides access to comprehensive financial market data including stocks, forex, ETFs, mutual funds, commodities, and cryptocurrencies.
Documentation

Twelve Data Rust Client

A Rust API client for Twelve Data — comprehensive financial market data API with access to stocks, forex, ETFs, mutual funds, commodities, and cryptocurrencies across 50+ countries.

This client features automatic builder pattern generation for all API operations, making it ergonomic to work with endpoints that have many optional parameters.

Features

  • Builder Pattern API: Clean, chainable parameter builders instead of functions with 20+ parameters
  • Full API Coverage: Complete access to all Twelve Data endpoints (time series, fundamentals, ETFs, technical indicators, etc.)
  • Type-Safe: Strongly typed request/response models generated from OpenAPI spec
  • Async: Built on reqwest with async/await support via tokio
  • Authentication: API key authentication via Authorization header

Installation

Add to your Cargo.toml:

[dependencies]
twelve-data-client = "0.3"
tokio = { version = "1.49.0", features = ["full"] }

Quick Start

use twelve_data_client::apis::{configuration, time_series_api};
use twelve_data_client::apis::time_series_api::GetTimeSeriesParams;
use twelve_data_client::models::GetTimeSeries200ResponseEnum;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Configure authentication
    let mut config = configuration::Configuration::new();
    config.api_key = Some(configuration::ApiKey {
        prefix: Some("apikey".to_string()),
        key: std::env::var("TWELVE_DATA_API_KEY")?,
    });

    // Build parameters using builder pattern
    let params = GetTimeSeriesParams::builder()
        .symbol("AAPL")
        .interval("1day")
        .outputsize(10)
        .build();

    // Make API call and handle response
    let response = time_series_api::get_time_series(&config, params).await?;
    
    match response {
        GetTimeSeries200ResponseEnum::GetTimeSeries200Response(data) => {
            println!("Symbol: {:?}", data.meta.as_ref().unwrap().symbol);
            println!("Data points: {}", data.values.as_ref().unwrap().len());
        }
        GetTimeSeries200ResponseEnum::ApiError(err) => {
            eprintln!("API Error: {}", err.message.unwrap_or_default());
        }
        GetTimeSeries200ResponseEnum::Text(csv) => {
            println!("CSV Response:\n{}", csv);
        }
    }
    
    Ok(())
}

Authentication

Get your API key from the Twelve Data dashboard.

Set it as an environment variable:

export TWELVE_DATA_API_KEY="your_api_key_here"

Or configure it directly:

config.api_key = Some(configuration::ApiKey {
    prefix: Some("apikey".to_string()),
    key: "your_api_key_here".to_string(),
});

Builder Pattern Example

Instead of this (many individual parameters):

// Old style - difficult to use
get_time_series(
    &config,
    "AAPL",
    "1day",
    None, None, None, None, None, 
    Some(10), 
    None, None, None, None, None, None, None, None, None
).await?

You get this (clean builder pattern):

use twelve_data_client::models::GetTimeSeries200ResponseEnum;

// New style - ergonomic and clear
let params = GetTimeSeriesParams::builder()
    .symbol("AAPL")
    .interval("1day")
    .outputsize(10)
    .build();

let response = get_time_series(&config, params).await?;

// Handle the response enum
match response {
    GetTimeSeries200ResponseEnum::GetTimeSeries200Response(data) => {
        // Process successful JSON response
        println!("Got {} data points", data.values.unwrap().len());
    }
    GetTimeSeries200ResponseEnum::ApiError(err) => {
        // Handle API errors
        eprintln!("Error: {}", err.message.unwrap_or_default());
    }
    GetTimeSeries200ResponseEnum::Text(csv) => {
        // Handle CSV format response
        println!("CSV data:\n{}", csv);
    }
}

Response Types

Most endpoints return an enum type with multiple variants to handle different response scenarios:

  • Success variant: Contains the actual data (e.g., GetTimeSeries200Response)
  • ApiError variant: Contains error information when the API returns an error
  • Text variant: Contains raw text (CSV) response when using format parameter

This approach provides type-safe error handling and format flexibility.

Available APIs

This client provides access to all Twelve Data endpoints organized by module:

  • time_series_api - Historical OHLCV data
  • fundamentals_api - Company financials, balance sheets, income statements
  • reference_data_api - Symbols, exchanges, currencies
  • technical_indicator_api - Technical analysis indicators
  • market_data_api - Real-time quotes and prices
  • etfs_api - ETF-specific data
  • mutual_funds_api - Mutual fund data
  • analysis_api - Analysis endpoints
  • regulatory_api - Regulatory filings
  • advanced_api - Advanced data endpoints

Code Generation

This client was automatically generated from the Twelve Data OpenAPI specification using a modified version of OpenAPI Generator.

Generation Process

The client was generated using openapi-generator-rust-builders, a fork of OpenAPI Generator that adds automatic builder pattern generation for all Rust API operations.

Generator Location: The generator is included as a git submodule at ./openapi-generator-rust-builders/

Build and generate:

# Build the modified generator
cd openapi-generator-rust-builders
./mvnw clean package -DskipTests

# Generate the client
cd ..
java -jar openapi-generator-rust-builders/modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
  -i openapi.json \
  -g rust \
  -o . \
  --additional-properties=packageName=twelve_data_client,packageVersion=0.1.0,library=reqwest

OpenAPI Specification Modification

The original Twelve Data OpenAPI spec required one minor modification to work with this generator:

Issue: The spec defined API key authentication in two places:

  • As a query parameter: ?apikey=value
  • As an Authorization header: Authorization: apikey value

This caused the generator to add the API key twice, which the Twelve Data API rejected.

Solution: Removed the queryParameters security scheme from the OpenAPI spec, keeping only the header-based authentication:

{
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "securitySchemes": {
    "ApiKeyAuth": {
      "type": "apiKey",
      "in": "header",
      "name": "Authorization"
    }
  }
}

The modified OpenAPI specification is saved as openapi.json in this repository.

Regenerating the Client

To regenerate the client after OpenAPI spec updates:

  1. Download the latest spec from Twelve Data:

    curl https://api.twelvedata.com/doc/swagger/openapi.json -o openapi.json
    
  2. Apply the security modification (remove query parameter security scheme)

  3. Rebuild the generator (if needed):

    cd openapi-generator-rust-builders
    ./mvnw clean package -DskipTests
    cd ..
    
  4. Generate the client:

    java -jar openapi-generator-rust-builders/modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
      -i openapi.json \
      -g rust \
      -o . \
      --additional-properties=packageName=twelve_data_client,packageVersion=0.1.0,library=reqwest
    
  5. Add tokio dev-dependency back to Cargo.toml (it gets overwritten):

    [dev-dependencies]
    tokio = { version = "1", features = ["full"] }
    

Examples

See the tests/ directory for complete working examples:

  • time_series_builder.rs - Fetching historical time series data with builder pattern, including JSON, error, and CSV response handling

Run the tests:

export TWELVE_DATA_API_KEY="your_api_key"
cargo test --test time_series_builder

Documentation

License

This client library is licensed under the Unlicense.

The Twelve Data API is a commercial service. See Twelve Data pricing for details.

Links