OilPriceAPI Docs
GitHub
GitHub
  • SDKs & Languages

    • SDKs & Language Guides
    • SDK Examples for Pagination and Error Handling
    • TypeScript Response Types
  • Language Guides

    • Java Oil Price API Integration
    • Go Oil Price API Integration
    • Rust Oil Price API Integration
    • PHP Oil Price API Integration
    • Ruby Oil Price API Integration
    • C# .NET Oil Price API Integration
    • R Language Oil Price API Integration

Rust Integration Guide

Integrate OilPriceAPI into your Rust applications to access the latest available crude oil prices, Brent crude data, natural gas rates, and commodity market information. Source publication and refresh schedules vary by dataset. Perfect for high-performance systems, CLI tools, and async services.

Dependencies

Add these to your Cargo.toml:

[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"

Quick Start

use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
use serde::Deserialize;
use std::env;

#[derive(Debug, Deserialize)]
struct Price {
    code: String,
    price: f64,
    currency: String,
    formatted: String,
}

#[derive(Debug, Deserialize)]
struct PriceResponse {
    status: String,
    data: Price,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = env::var("OILPRICEAPI_KEY")?;

    let client = reqwest::Client::new();
    let response: PriceResponse = client
        .get("https://api.oilpriceapi.com/v1/prices/latest")
        .query(&[("by_code", "WTI_USD")])
        .header(AUTHORIZATION, format!("Token {}", api_key))
        .send()
        .await?
        .json()
        .await?;

    println!("WTI Price: {}", response.data.formatted);
    Ok(())
}

Complete API Client

Create a full-featured async client:

use reqwest::{Client, StatusCode};
use serde::{Deserialize, Serialize};
use std::env;
use std::time::Duration;
use thiserror::Error;

// Error types
#[derive(Error, Debug)]
pub enum OilPriceError {
    #[error("HTTP request failed: {0}")]
    RequestError(#[from] reqwest::Error),

    #[error("API error ({status}): {message}")]
    ApiError { status: u16, message: String },

    #[error("Invalid API key")]
    Unauthorized,

    #[error("Commodity not found: {0}")]
    NotFound(String),

    #[error("Rate limit exceeded")]
    RateLimited,

    #[error("Environment variable not found: {0}")]
    EnvError(#[from] std::env::VarError),
}

// Response types
#[derive(Debug, Deserialize, Clone)]
pub struct Price {
    pub code: String,
    pub price: f64,
    pub currency: String,
    pub unit: String,
    pub formatted: String,
    pub created_at: String,
    #[serde(default)]
    pub change_24h: Option<f64>,
    #[serde(default)]
    pub change_24h_pct: Option<f64>,
}

#[derive(Debug, Deserialize)]
struct PriceResponse {
    status: String,
    data: Price,
}

#[derive(Debug, Deserialize, Clone)]
pub struct HistoricalPrice {
    pub date: String,
    pub open: f64,
    pub high: f64,
    pub low: f64,
    pub close: f64,
    pub volume: Option<i64>,
}

#[derive(Debug, Deserialize)]
struct HistoricalData {
    code: String,
    currency: String,
    unit: String,
    prices: Vec<HistoricalPrice>,
}

#[derive(Debug, Deserialize)]
struct HistoricalResponse {
    status: String,
    data: HistoricalData,
}

#[derive(Debug, Deserialize)]
pub struct Commodity {
    pub code: String,
    pub name: String,
    pub category: String,
    pub currency: String,
    pub unit: String,
}

#[derive(Debug, Deserialize)]
struct CommoditiesResponse {
    status: String,
    data: Vec<Commodity>,
}

#[derive(Debug, Deserialize)]
struct ErrorResponse {
    error: ErrorDetail,
}

#[derive(Debug, Deserialize)]
struct ErrorDetail {
    code: String,
    message: String,
}

// API Client
pub struct OilPriceClient {
    client: Client,
    api_key: String,
    base_url: String,
}

impl OilPriceClient {
    /// Create a new client with the given API key
    pub fn new(api_key: impl Into<String>) -> Self {
        Self {
            client: Client::builder()
                .timeout(Duration::from_secs(30))
                .build()
                .expect("Failed to create HTTP client"),
            api_key: api_key.into(),
            base_url: "https://api.oilpriceapi.com/v1".to_string(),
        }
    }

    /// Create a client using OILPRICEAPI_KEY environment variable
    pub fn from_env() -> Result<Self, OilPriceError> {
        let api_key = env::var("OILPRICEAPI_KEY")?;
        Ok(Self::new(api_key))
    }

    /// Get latest price for a commodity
    pub async fn get_latest_price(&self, code: &str) -> Result<Price, OilPriceError> {
        let url = format!("{}/prices/latest", self.base_url);
        let response = self
            .client
            .get(&url)
            .query(&[("by_code", code)])
            .header("Authorization", format!("Token {}", self.api_key))
            .header("X-Client-Name", "rust-client")
            .header("X-Client-Version", "1.0.0")
            .send()
            .await?;

        self.handle_response::<PriceResponse>(response, code)
            .await
            .map(|r| r.data)
    }

    /// Get multiple prices at once
    pub async fn get_prices(&self, codes: &[&str]) -> Result<Vec<Price>, OilPriceError> {
        let futures: Vec<_> = codes.iter().map(|code| self.get_latest_price(code)).collect();
        let results = futures::future::join_all(futures).await;

        results.into_iter().collect()
    }

    /// Get historical prices for a commodity
    pub async fn get_historical_prices(
        &self,
        code: &str,
        start_date: Option<&str>,
        end_date: Option<&str>,
    ) -> Result<Vec<HistoricalPrice>, OilPriceError> {
        let url = format!("{}/prices/historical", self.base_url);
        let mut request = self
            .client
            .get(&url)
            .query(&[("by_code", code)])
            .header("Authorization", format!("Token {}", self.api_key));

        if let Some(start) = start_date {
            request = request.query(&[("start_date", start)]);
        }
        if let Some(end) = end_date {
            request = request.query(&[("end_date", end)]);
        }

        let response = request.send().await?;
        self.handle_response::<HistoricalResponse>(response, code)
            .await
            .map(|r| r.data.prices)
    }

    /// Get all available commodities
    pub async fn get_commodities(&self) -> Result<Vec<Commodity>, OilPriceError> {
        let url = format!("{}/commodities", self.base_url);
        let response = self
            .client
            .get(&url)
            .header("Authorization", format!("Token {}", self.api_key))
            .send()
            .await?;

        self.handle_response::<CommoditiesResponse>(response, "commodities")
            .await
            .map(|r| r.data)
    }

    // Handle HTTP response and errors
    async fn handle_response<T: for<'de> Deserialize<'de>>(
        &self,
        response: reqwest::Response,
        context: &str,
    ) -> Result<T, OilPriceError> {
        let status = response.status();

        match status {
            StatusCode::OK => Ok(response.json().await?),
            StatusCode::UNAUTHORIZED => Err(OilPriceError::Unauthorized),
            StatusCode::NOT_FOUND => Err(OilPriceError::NotFound(context.to_string())),
            StatusCode::TOO_MANY_REQUESTS => Err(OilPriceError::RateLimited),
            _ => {
                let body = response.text().await.unwrap_or_default();
                Err(OilPriceError::ApiError {
                    status: status.as_u16(),
                    message: body,
                })
            }
        }
    }
}

Usage Examples

Basic Usage

use oilpriceapi::OilPriceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = OilPriceClient::from_env()?;

    // Get WTI price
    let wti = client.get_latest_price("WTI_USD").await?;
    println!("WTI: {} ({:+.2}%)",
        wti.formatted,
        wti.change_24h_pct.unwrap_or(0.0)
    );

    // Get Brent price
    let brent = client.get_latest_price("BRENT_CRUDE_USD").await?;
    println!("Brent: {}", brent.formatted);

    Ok(())
}

Concurrent Requests

use futures::future::join_all;
use oilpriceapi::OilPriceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = OilPriceClient::from_env()?;

    let codes = vec!["WTI_USD", "BRENT_CRUDE_USD", "NATURAL_GAS_USD", "DIESEL_USD"];

    // Fetch all prices concurrently
    let futures: Vec<_> = codes
        .iter()
        .map(|code| client.get_latest_price(code))
        .collect();

    let results = join_all(futures).await;

    for (code, result) in codes.iter().zip(results.iter()) {
        match result {
            Ok(price) => println!("{}: {}", code, price.formatted),
            Err(e) => eprintln!("{}: Error - {}", code, e),
        }
    }

    Ok(())
}

Historical Data Analysis

use oilpriceapi::OilPriceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = OilPriceClient::from_env()?;

    // Get last 30 days of WTI prices
    let prices = client
        .get_historical_prices("WTI_USD", Some("2025-01-01"), Some("2025-01-30"))
        .await?;

    // Calculate statistics
    let closes: Vec<f64> = prices.iter().map(|p| p.close).collect();
    let avg = closes.iter().sum::<f64>() / closes.len() as f64;
    let min = closes.iter().cloned().fold(f64::INFINITY, f64::min);
    let max = closes.iter().cloned().fold(f64::NEG_INFINITY, f64::max);

    println!("WTI Statistics (30 days):");
    println!("  Average: ${:.2}", avg);
    println!("  Min: ${:.2}", min);
    println!("  Max: ${:.2}", max);
    println!("  Range: ${:.2}", max - min);

    Ok(())
}

Error Handling

use oilpriceapi::{OilPriceClient, OilPriceError};

async fn get_price_safe(client: &OilPriceClient, code: &str) -> Option<f64> {
    match client.get_latest_price(code).await {
        Ok(price) => Some(price.price),
        Err(OilPriceError::Unauthorized) => {
            eprintln!("Invalid API key - check OILPRICEAPI_KEY");
            None
        }
        Err(OilPriceError::NotFound(code)) => {
            eprintln!("Commodity not found: {}", code);
            None
        }
        Err(OilPriceError::RateLimited) => {
            eprintln!("Rate limited - waiting before retry");
            tokio::time::sleep(std::time::Duration::from_secs(60)).await;
            // Retry once
            client.get_latest_price(code).await.ok().map(|p| p.price)
        }
        Err(e) => {
            eprintln!("API error: {}", e);
            None
        }
    }
}

Retry with Exponential Backoff

use std::time::Duration;
use tokio::time::sleep;

async fn with_retry<T, F, Fut>(
    operation: F,
    max_retries: u32,
) -> Result<T, OilPriceError>
where
    F: Fn() -> Fut,
    Fut: std::future::Future<Output = Result<T, OilPriceError>>,
{
    let mut attempt = 0;

    loop {
        match operation().await {
            Ok(result) => return Ok(result),
            Err(OilPriceError::RateLimited) if attempt < max_retries => {
                attempt += 1;
                let delay = Duration::from_secs(2u64.pow(attempt));
                println!("Rate limited. Retrying in {:?}...", delay);
                sleep(delay).await;
            }
            Err(e) => return Err(e),
        }
    }
}

// Usage
let client = OilPriceClient::from_env()?;
let price = with_retry(|| client.get_latest_price("WTI_USD"), 3).await?;

CLI Tool Example

Create a simple CLI for fetching prices:

use clap::Parser;
use oilpriceapi::OilPriceClient;

#[derive(Parser)]
#[command(name = "oilprice")]
#[command(about = "Fetch oil and commodity prices")]
struct Cli {
    /// Commodity codes to fetch
    #[arg(required = true)]
    codes: Vec<String>,

    /// Output as JSON
    #[arg(short, long)]
    json: bool,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cli = Cli::parse();
    let client = OilPriceClient::from_env()?;

    for code in &cli.codes {
        match client.get_latest_price(code).await {
            Ok(price) => {
                if cli.json {
                    println!("{}", serde_json::to_string_pretty(&price)?);
                } else {
                    println!("{}: {} ({})",
                        price.code,
                        price.formatted,
                        price.created_at
                    );
                }
            }
            Err(e) => eprintln!("Error fetching {}: {}", code, e),
        }
    }

    Ok(())
}

Actix-web Integration

use actix_web::{get, web, App, HttpResponse, HttpServer};
use oilpriceapi::OilPriceClient;
use std::sync::Arc;

struct AppState {
    oil_client: OilPriceClient,
}

#[get("/prices/{code}")]
async fn get_price(
    data: web::Data<Arc<AppState>>,
    path: web::Path<String>,
) -> HttpResponse {
    let code = path.into_inner();

    match data.oil_client.get_latest_price(&code).await {
        Ok(price) => HttpResponse::Ok().json(price),
        Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let client = OilPriceClient::from_env().expect("API key required");
    let state = Arc::new(AppState { oil_client: client });

    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(state.clone()))
            .service(get_price)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Common Commodity Codes

CodeDescription
WTI_USDWest Texas Intermediate
BRENT_CRUDE_USDBrent Crude
NATURAL_GAS_USDHenry Hub Natural Gas
HEATING_OIL_USDHeating Oil
DIESEL_USDUltra Low Sulfur Diesel
GASOLINE_USDRBOB Gasoline

View all commodity codes

Related

  • API Reference - Full endpoint documentation
  • Error Codes - Complete error handling guide
  • Rate Limits - Request limits by plan
Last Updated: 8/23/26, 10:45 PM
Prev
Go Oil Price API Integration
Next
PHP Oil Price API Integration