DocsIntegration

Get exchange rates in Rust with reqwest and serde

A blocking client for EUR to JPY

30 Oct 2026 · 3 min read

Use reqwest's blocking client to request EUR to JPY, then deserialize the response with serde. The program reads an API key from the environment and prints the exchange rate and a converted euro amount. It also prints the market session and the oldest contributing observation so you can read the rate alongside its timing.

Add reqwest and serde

Put the dependencies in Cargo.toml. The sample uses reqwest 0.12 with the blocking and json features, plus serde 1 with derive. These match the calls and the response struct in the Rust code.

The blocking feature supports reqwest::blocking::Client, and the sample uses json() to deserialize the response. Serde's Deserialize derive applies to Latest, the struct that holds the fields this program reads. Keep these dependencies with the package configuration shown in the snippet before you add the request code.

Cargo.toml
[package]name = "fx-rate"version = "0.1.0"edition = "2021"[dependencies]reqwest = { version = "0.12", features = ["blocking", "json"] }serde = { version = "1", features = ["derive"] }

Request EUR to JPY

Put the client code in src/main.rs. It sends GET https://api.exchangerate.dev/v1/latest/EUR?symbols=JPY and passes the key through bearer_auth. The key goes in the Authorization header as a bearer token.

The latest function takes the base currency, quote currency and key. Its response struct contains rates, market_session and data_updated_at. After the request, error_for_status() turns a non-2xx response into an error before the program attempts to deserialize the JSON.

In main, the program requests EUR as the base and JPY as the quote, reads the JPY entry from rates, and multiplies the sample euro amount by that rate.

src/main.rs
use std::collections::HashMap;use std::env;use std::error::Error;use serde::Deserialize;#[derive(Deserialize)]struct Latest {    rates: HashMap<String, f64>,    market_session: String,    data_updated_at: String,}fn latest(base: &str, quote: &str, key: &str) -> Result<Latest, Box<dyn Error>> {    let url = format!("https://api.exchangerate.dev/v1/latest/{base}?symbols={quote}");    let response = reqwest::blocking::Client::new()        .get(url)        .bearer_auth(key)        .send()?        .error_for_status()?;    Ok(response.json()?)}fn main() -> Result<(), Box<dyn Error>> {    let key = env::var("EXCHANGERATE_API_KEY")?;    let data = latest("EUR", "JPY", &key)?;    let rate = data.rates["JPY"];    println!("1 EUR = {rate} JPY ({}, updated {})", data.market_session, data.data_updated_at);    println!("1000 EUR = {:.0} JPY", 1000.0 * rate);    Ok(())}

Set the key and run the program

Set EXCHANGERATE_API_KEY in the environment, then run cargo run. Replace your_key in the shell snippet with your API key. The program reads that variable through env::var and passes its value to the request function.

The environment variable must be available when the program runs. If it is absent, the environment lookup returns an error before the request. Request errors, HTTP status errors and JSON deserialization errors also propagate through the sample's Result return values. The rate and converted amount print after the request and deserialization succeed.

Shell
export EXCHANGERATE_API_KEY="your_key"cargo run

Read the rate and converted amount

The first output line gives JPY per EUR, followed by market_session and data_updated_at. The second line gives the sample euro amount multiplied by the returned JPY rate. Its formatting prints the converted amount with no decimal places.

The output snippet contains example values. Read your run's rate together with its session and observation time, since those fields belong to the response your program received.

The converted amount uses indicative mid-market figures. Banks, cards and transfer services apply their own spread and fees, so their amounts can differ from this calculation. These rates are not for settlement or trading.

Output
1 EUR = 175.604 JPY (open, updated 2026-10-23T18:00:59Z)1000 EUR = 175604 JPY

Check the observation time

data_updated_at is the oldest contributing observation. The sample prints it beside market_session, so the rate's output includes timing information as well as the numeric quote. The response also has timestamp and effective_at; the sample does not deserialize those fields.

Other response fields are result, base, source, sources, stale, derived_symbols and notice. The sources field has a source per symbol, and stale is an object per symbol. The Latest struct selects the fields needed for this program's calculation and printed output.

Choose access for your request volume

A free key has 5,000 requests a month and 10 requests a minute. Its rates are 15 minutes late. Paid plans are live. The blocking client sends the same request with the key supplied through the environment.

Keyless access allows 10 requests a minute and 100 an hour per IP, with rates 15 minutes late. This sample reads a key and sends a bearer header, so use an API key when you run it as written. The API reference is the related documentation for the endpoint.

Questions

Where does the API key go?

Set it as `EXCHANGERATE_API_KEY` before running the program. The code reads the variable and uses `bearer_auth` to send its value in the `Authorization` header. It does not add the key to the URL.

What happens if the API returns an HTTP error?

`error_for_status()` turns a non-2xx response into an error. The sample propagates that error through its return value, before JSON deserialization and before either output line prints.

What does the converted amount mean?

It is the sample euro amount multiplied by the JPY rate returned for EUR. The printed amount has no decimal places. It uses indicative mid-market figures; banks, cards and transfer services apply their own spread and fees.

Are free-key rates live?

Free-key rates are 15 minutes late, and keyless rates have the same delay. Paid plans are live. The sample prints `data_updated_at`, the oldest contributing observation, beside the market session.

Keep reading

Get a free API key

Free has 5,000 requests a month and 10 requests a minute. No credit card is required.

Get a free key