Java Oil Price API
Integrate real-time oil and commodity prices into your Java applications. Enterprise-ready with Spring Boot, async processing, and comprehensive error handling.
Quick Start
1. Add Dependencies
<!-- Maven dependencies -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
2. Java Features
- Enterprise-grade error handling
- Spring Boot integration
- Async and caching support
Basic Integration
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class OilPriceAPI {
private static final String BASE_URL = "https://api.oilpriceapi.com";
private final String apiKey;
private final Gson gson;
public OilPriceAPI(String apiKey) {
this.apiKey = apiKey;
this.gson = new Gson();
}
public ApiResponse getBrentPrice() throws IOException {
return makeRequest("/prices");
}
public ApiResponse getCommodityHealth() throws IOException {
return makeRequest("/health");
}
public CommodityPrice getWTIPrice() throws IOException {
ApiResponse healthResponse = getCommodityHealth();
JsonObject healthData = JsonParser.parseString(healthResponse.getBody()).getAsJsonObject();
JsonObject metrics = healthData.getAsJsonObject("metrics");
if (metrics == null) return null;
JsonObject commodityHealth = metrics.getAsJsonObject("commodity_health");
if (commodityHealth == null) return null;
JsonObject wtiData = commodityHealth.getAsJsonObject("WTI_USD");
if (wtiData == null) return null;
double latestPrice = wtiData.get("latest_price").getAsDouble();
String lastUpdate = wtiData.get("last_update").getAsString();
return new CommodityPrice(
latestPrice / 100.0, // Convert from cents
lastUpdate,
"USD",
"barrel"
);
}
public Map<String, CommodityPrice> getAllCommodities() throws IOException {
Map<String, CommodityPrice> commodities = new HashMap<>();
// Get Brent from prices endpoint
ApiResponse brentResponse = getBrentPrice();
JsonObject brentData = JsonParser.parseString(brentResponse.getBody()).getAsJsonObject();
JsonObject brentPriceData = brentData.getAsJsonObject("data");
if (brentPriceData != null) {
commodities.put("brent_crude", new CommodityPrice(
brentPriceData.get("price").getAsDouble(),
brentPriceData.get("timestamp").getAsString(),
brentPriceData.get("currency").getAsString(),
"barrel"
));
}
// Get other commodities from health endpoint
ApiResponse healthResponse = getCommodityHealth();
JsonObject healthData = JsonParser.parseString(healthResponse.getBody()).getAsJsonObject();
JsonObject metrics = healthData.getAsJsonObject("metrics");
if (metrics != null) {
JsonObject commodityHealth = metrics.getAsJsonObject("commodity_health");
if (commodityHealth != null) {
for (String key : commodityHealth.keySet()) {
JsonObject commodity = commodityHealth.getAsJsonObject(key);
if (commodity.has("latest_price")) {
double scale = isCurrencyPair(key) ? 10000.0 : 100.0;
double price = commodity.get("latest_price").getAsDouble() / scale;
commodities.put(key.toLowerCase(), new CommodityPrice(
price,
commodity.get("last_update").getAsString(),
"USD",
getUnit(key)
));
}
}
}
}
return commodities;
}
private ApiResponse makeRequest(String endpoint) throws IOException {
URL url = new URL(BASE_URL + endpoint);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Set request properties
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Token " + apiKey);
connection.setRequestProperty("Content-Type", "application/json");
connection.setConnectTimeout(10000); // 10 seconds
connection.setReadTimeout(10000);
int responseCode = connection.getResponseCode();
StringBuilder response = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
responseCode >= 200 && responseCode < 300 ?
connection.getInputStream() : connection.getErrorStream()))) {
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
}
return new ApiResponse(responseCode, response.toString());
}
private boolean isCurrencyPair(String commodityKey) {
return commodityKey.equals("EUR_USD") || commodityKey.equals("GBP_USD");
}
private String getUnit(String commodityKey) {
Map<String, String> units = new HashMap<>();
units.put("WTI_USD", "barrel");
units.put("NATURAL_GAS_USD", "MMBtu");
units.put("GOLD_USD", "ounce");
units.put("EUR_USD", "USD");
units.put("GBP_USD", "USD");
return units.getOrDefault(commodityKey, "unit");
}
// Data classes
public static class ApiResponse {
private final int statusCode;
private final String body;
public ApiResponse(int statusCode, String body) {
this.statusCode = statusCode;
this.body = body;
}
public int getStatusCode() { return statusCode; }
public String getBody() { return body; }
public boolean isSuccessful() { return statusCode >= 200 && statusCode < 300; }
}
public static class CommodityPrice {
private final double price;
private final String timestamp;
private final String currency;
private final String unit;
public CommodityPrice(double price, String timestamp, String currency, String unit) {
this.price = price;
this.timestamp = timestamp;
this.currency = currency;
this.unit = unit;
}
// Getters
public double getPrice() { return price; }
public String getTimestamp() { return timestamp; }
public String getCurrency() { return currency; }
public String getUnit() { return unit; }
@Override
public String toString() {
return String.format("%.2f %s per %s (updated: %s)",
price, currency, unit, timestamp);
}
}
// Usage example
public static void main(String[] args) {
try {
OilPriceAPI api = new OilPriceAPI("YOUR_API_KEY_HERE");
// Get Brent crude price
ApiResponse brentResponse = api.getBrentPrice();
if (brentResponse.isSuccessful()) {
System.out.println("Brent Response: " + brentResponse.getBody());
}
// Get WTI price
CommodityPrice wtiPrice = api.getWTIPrice();
if (wtiPrice != null) {
System.out.println("WTI: " + wtiPrice);
}
// Get all commodities
Map<String, CommodityPrice> allCommodities = api.getAllCommodities();
allCommodities.forEach((name, price) ->
System.out.println(name.toUpperCase() + ": " + price));
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
}
Spring Boot Integration
Production-ready Spring Boot service with caching and REST endpoints:
// pom.xml dependencies
/*
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
*/
package com.example.oilprices;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@SpringBootApplication
@EnableCaching
public class OilPriceApplication {
public static void main(String[] args) {
SpringApplication.run(OilPriceApplication.class, args);
}
}
@Service
public class OilPriceService {
private static final String BASE_URL = "https://api.oilpriceapi.com";
private final OkHttpClient httpClient;
private final ObjectMapper objectMapper;
private final String apiKey;
public OilPriceService(@Value("${oil.price.api.key}") String apiKey) {
this.apiKey = apiKey;
this.objectMapper = new ObjectMapper();
this.httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
}
@Cacheable(value = "brentPrice", unless = "#result == null")
public PriceResponse getBrentPrice() throws OilPriceException {
try {
Request request = new Request.Builder()
.url(BASE_URL + "/prices")
.header("Authorization", "Token " + apiKey)
.header("Content-Type", "application/json")
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new OilPriceException("HTTP " + response.code() + ": " + response.message());
}
String responseBody = response.body().string();
return objectMapper.readValue(responseBody, PriceResponse.class);
}
} catch (IOException e) {
throw new OilPriceException("Failed to fetch Brent price", e);
}
}
@Cacheable(value = "commodityHealth", unless = "#result == null")
public HealthResponse getCommodityHealth() throws OilPriceException {
try {
Request request = new Request.Builder()
.url(BASE_URL + "/health")
.header("Authorization", "Token " + apiKey)
.header("Content-Type", "application/json")
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new OilPriceException("HTTP " + response.code() + ": " + response.message());
}
String responseBody = response.body().string();
return objectMapper.readValue(responseBody, HealthResponse.class);
}
} catch (IOException e) {
throw new OilPriceException("Failed to fetch commodity health", e);
}
}
@Cacheable(value = "allCommodities", unless = "#result.isEmpty()")
public Map<String, CommodityPrice> getAllCommodities() throws OilPriceException {
Map<String, CommodityPrice> commodities = new HashMap<>();
// Get Brent price
PriceResponse brentResponse = getBrentPrice();
if (brentResponse.getData() != null) {
commodities.put("brent_crude", new CommodityPrice(
brentResponse.getData().getPrice(),
brentResponse.getData().getTimestamp(),
brentResponse.getData().getCurrency(),
"barrel"
));
}
// Get other commodities from health endpoint
HealthResponse healthResponse = getCommodityHealth();
if (healthResponse.getMetrics() != null &&
healthResponse.getMetrics().getCommodityHealth() != null) {
Map<String, JsonNode> healthData = healthResponse.getMetrics().getCommodityHealth();
healthData.forEach((key, data) -> {
if (data.has("latest_price")) {
double scale = isCurrencyPair(key) ? 10000.0 : 100.0;
double price = data.get("latest_price").asDouble() / scale;
commodities.put(key.toLowerCase(), new CommodityPrice(
price,
data.get("last_update").asText(),
"USD",
getUnit(key)
));
}
});
}
return commodities;
}
public CommodityPrice getCommodityPrice(String commodity) throws OilPriceException {
Map<String, CommodityPrice> allPrices = getAllCommodities();
CommodityPrice price = allPrices.get(commodity.toLowerCase());
if (price == null) {
throw new OilPriceException("Commodity not found: " + commodity);
}
return price;
}
private boolean isCurrencyPair(String commodityKey) {
return "EUR_USD".equals(commodityKey) || "GBP_USD".equals(commodityKey);
}
private String getUnit(String commodityKey) {
Map<String, String> units = Map.of(
"WTI_USD", "barrel",
"NATURAL_GAS_USD", "MMBtu",
"GOLD_USD", "ounce",
"EUR_USD", "USD",
"GBP_USD", "USD"
);
return units.getOrDefault(commodityKey, "unit");
}
}
// REST Controller
@RestController
@RequestMapping("/api/oil-prices")
@CrossOrigin(origins = "*")
public class OilPriceController {
private final OilPriceService oilPriceService;
public OilPriceController(OilPriceService oilPriceService) {
this.oilPriceService = oilPriceService;
}
@GetMapping
public ResponseEntity<Map<String, Object>> getAllPrices() {
try {
Map<String, CommodityPrice> prices = oilPriceService.getAllCommodities();
Map<String, Object> response = Map.of(
"status", "success",
"data", prices,
"timestamp", LocalDateTime.now()
);
return ResponseEntity.ok(response);
} catch (OilPriceException e) {
Map<String, Object> errorResponse = Map.of(
"status", "error",
"message", e.getMessage(),
"timestamp", LocalDateTime.now()
);
return ResponseEntity.status(500).body(errorResponse);
}
}
@GetMapping("/{commodity}")
public ResponseEntity<Map<String, Object>> getCommodityPrice(@PathVariable String commodity) {
try {
CommodityPrice price = oilPriceService.getCommodityPrice(commodity);
Map<String, Object> response = Map.of(
"status", "success",
"commodity", commodity,
"data", price,
"timestamp", LocalDateTime.now()
);
return ResponseEntity.ok(response);
} catch (OilPriceException e) {
Map<String, Object> errorResponse = Map.of(
"status", "error",
"message", e.getMessage(),
"timestamp", LocalDateTime.now()
);
return ResponseEntity.status(e.getMessage().contains("not found") ? 404 : 500)
.body(errorResponse);
}
}
@GetMapping("/brent")
public ResponseEntity<PriceResponse> getBrentPrice() {
try {
PriceResponse response = oilPriceService.getBrentPrice();
return ResponseEntity.ok(response);
} catch (OilPriceException e) {
return ResponseEntity.status(500).build();
}
}
}
// Data Transfer Objects
public class PriceResponse {
private String status;
private PriceData data;
// Getters and setters
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public PriceData getData() { return data; }
public void setData(PriceData data) { this.data = data; }
}
public class PriceData {
private double price;
private String timestamp;
private String currency;
private String unit;
// Getters and setters
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public String getTimestamp() { return timestamp; }
public void setTimestamp(String timestamp) { this.timestamp = timestamp; }
public String getCurrency() { return currency; }
public void setCurrency(String currency) { this.currency = currency; }
public String getUnit() { return unit; }
public void setUnit(String unit) { this.unit = unit; }
}
public class HealthResponse {
private String status;
private Metrics metrics;
// Getters and setters
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public Metrics getMetrics() { return metrics; }
public void setMetrics(Metrics metrics) { this.metrics = metrics; }
}
public class Metrics {
@JsonProperty("commodity_health")
private Map<String, JsonNode> commodityHealth;
public Map<String, JsonNode> getCommodityHealth() { return commodityHealth; }
public void setCommodityHealth(Map<String, JsonNode> commodityHealth) {
this.commodityHealth = commodityHealth;
}
}
public class CommodityPrice {
private final double price;
private final String timestamp;
private final String currency;
private final String unit;
public CommodityPrice(double price, String timestamp, String currency, String unit) {
this.price = price;
this.timestamp = timestamp;
this.currency = currency;
this.unit = unit;
}
// Getters
public double getPrice() { return price; }
public String getTimestamp() { return timestamp; }
public String getCurrency() { return currency; }
public String getUnit() { return unit; }
}
// Custom Exception
public class OilPriceException extends Exception {
public OilPriceException(String message) {
super(message);
}
public OilPriceException(String message, Throwable cause) {
super(message, cause);
}
}
// application.properties
/*
oil.price.api.key=YOUR_API_KEY_HERE
spring.cache.type=simple
logging.level.com.example.oilprices=DEBUG
*/
Async Processing with OkHttp
High-performance async client with CompletableFuture:
import okhttp3.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class AsyncOilPriceClient {
private static final String BASE_URL = "https://api.oilpriceapi.com";
private final OkHttpClient httpClient;
private final Gson gson;
private final String apiKey;
public AsyncOilPriceClient(String apiKey) {
this.apiKey = apiKey;
this.gson = new GsonBuilder()
.setPrettyPrinting()
.create();
this.httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
}
public CompletableFuture<PriceResponse> getBrentPriceAsync() {
CompletableFuture<PriceResponse> future = new CompletableFuture<>();
Request request = buildRequest("/prices");
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
future.completeExceptionally(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) {
future.completeExceptionally(new IOException("HTTP " + response.code()));
return;
}
String json = responseBody.string();
PriceResponse priceResponse = gson.fromJson(json, PriceResponse.class);
future.complete(priceResponse);
} catch (Exception e) {
future.completeExceptionally(e);
}
}
});
return future;
}
public CompletableFuture<HealthResponse> getHealthAsync() {
CompletableFuture<HealthResponse> future = new CompletableFuture<>();
Request request = buildRequest("/health");
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
future.completeExceptionally(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) {
future.completeExceptionally(new IOException("HTTP " + response.code()));
return;
}
String json = responseBody.string();
HealthResponse healthResponse = gson.fromJson(json, HealthResponse.class);
future.complete(healthResponse);
} catch (Exception e) {
future.completeExceptionally(e);
}
}
});
return future;
}
public CompletableFuture<CombinedPriceData> getAllPricesAsync() {
CompletableFuture<PriceResponse> brentFuture = getBrentPriceAsync();
CompletableFuture<HealthResponse> healthFuture = getHealthAsync();
return CompletableFuture.allOf(brentFuture, healthFuture)
.thenApply(v -> {
try {
PriceResponse brentResponse = brentFuture.get();
HealthResponse healthResponse = healthFuture.get();
return new CombinedPriceData(brentResponse, healthResponse);
} catch (Exception e) {
throw new RuntimeException("Failed to combine price data", e);
}
});
}
private Request buildRequest(String endpoint) {
return new Request.Builder()
.url(BASE_URL + endpoint)
.header("Authorization", "Token " + apiKey)
.header("Content-Type", "application/json")
.header("User-Agent", "OilPriceAPI-Java-Client/1.0")
.build();
}
public void close() {
httpClient.dispatcher().executorService().shutdown();
httpClient.connectionPool().evictAll();
}
// Usage example with async processing
public static void main(String[] args) {
AsyncOilPriceClient client = new AsyncOilPriceClient("YOUR_API_KEY_HERE");
try {
// Get all prices asynchronously
CompletableFuture<CombinedPriceData> pricesFuture = client.getAllPricesAsync();
pricesFuture.thenAccept(data -> {
System.out.println("=== Live Oil Prices ===");
// Print Brent crude price
if (data.getBrentResponse() != null && data.getBrentResponse().getData() != null) {
PriceData brent = data.getBrentResponse().getData();
System.out.printf("Brent Crude: $%.2f/%s%n",
brent.getPrice(), brent.getUnit());
}
// Print WTI and other commodities from health data
data.extractCommodityPrices().forEach((name, price) -> {
System.out.printf("%s: $%.2f/%s%n",
name.replace("_", " ").toUpperCase(),
price.getPrice(),
price.getUnit());
});
}).exceptionally(throwable -> {
System.err.println("Error fetching prices: " + throwable.getMessage());
throwable.printStackTrace();
return null;
}).join(); // Wait for completion
} finally {
client.close();
}
}
}
class CombinedPriceData {
private final PriceResponse brentResponse;
private final HealthResponse healthResponse;
public CombinedPriceData(PriceResponse brentResponse, HealthResponse healthResponse) {
this.brentResponse = brentResponse;
this.healthResponse = healthResponse;
}
public PriceResponse getBrentResponse() { return brentResponse; }
public HealthResponse getHealthResponse() { return healthResponse; }
public Map<String, CommodityPrice> extractCommodityPrices() {
Map<String, CommodityPrice> prices = new HashMap<>();
if (healthResponse != null && healthResponse.getMetrics() != null) {
Map<String, Object> commodityHealth = healthResponse.getMetrics().getCommodityHealth();
if (commodityHealth != null) {
commodityHealth.forEach((key, value) -> {
if (value instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> data = (Map<String, Object>) value;
if (data.containsKey("latest_price")) {
double latestPrice = ((Number) data.get("latest_price")).doubleValue();
double scale = isCurrencyPair(key) ? 10000.0 : 100.0;
double price = latestPrice / scale;
prices.put(key.toLowerCase(), new CommodityPrice(
price,
(String) data.get("last_update"),
"USD",
getUnit(key)
));
}
}
});
}
}
return prices;
}
private boolean isCurrencyPair(String key) {
return "EUR_USD".equals(key) || "GBP_USD".equals(key);
}
private String getUnit(String key) {
Map<String, String> units = Map.of(
"WTI_USD", "barrel",
"NATURAL_GAS_USD", "MMBtu",
"GOLD_USD", "ounce",
"EUR_USD", "USD",
"GBP_USD", "USD"
);
return units.getOrDefault(key, "unit");
}
}
Available Commodities
Brent Crude Oil
North Sea Brent crude oil, the global benchmark for oil pricing representing ~60% of internationally traded crude oil.
WTI Crude Oil
West Texas Intermediate crude oil, the primary benchmark for North American oil markets and NYMEX futures.
Dubai Crude Oil
Dubai crude oil benchmark for Middle Eastern crude oil pricing and Asian markets.
Natural Gas
NYMEX Henry Hub natural gas futures, the primary pricing benchmark for North American natural gas markets.
Natural Gas (UK)
UK natural gas pricing in British pence per therm.
Dutch TTF Gas
Dutch Title Transfer Facility (TTF) natural gas futures, the European gas pricing benchmark.
Gasoline RBOB
Reformulated Blendstock for Oxygenate Blending (RBOB) gasoline futures.
Heating Oil
No. 2 heating oil futures, a key refined petroleum product for heating and industrial use.
Coal
Coal futures pricing for thermal coal used in power generation.
Gold
Gold futures pricing, a key precious metal and safe-haven asset.
EUR/USD
Euro to US Dollar exchange rate, the most traded currency pair globally.
GBP/USD
British Pound to US Dollar exchange rate, also known as "Cable".
Java Best Practices
Error Handling
- Use custom exceptions for API errors
- Implement proper resource management
- Log with appropriate levels
Performance
- Use connection pooling with OkHttp
- Implement caching with Spring Cache
- Use async processing for concurrent requests
Ready to Start Building?
Get your free API key and start integrating real-time commodity prices into your Java applications today.