Oil Price API Documentation - Quick Start in 5 Minutes | REST API
GitHub
GitHub
  • SDKs & Languages

    • SDKs & Language Guides
    • TypeScript Response Types
  • Language Guides

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

Rust Integration Guide

Integrate OilPriceAPI into your Rust applications to access real-time crude oil prices, Brent crude data, natural gas rates, and commodity market information. 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("OILPRICE_API_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 OILPRICE_API_KEY environment variable
    pub fn from_env() -> Result<Self, OilPriceError> {
        let api_key = env::var("OILPRICE_API_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 OILPRICE_API_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: 12/30/25, 12:33 PM
Prev
Go Oil Price API Integration | OilPriceAPI
Next
PHP Oil Price API Integration | OilPriceAPI