In this mini-project, you will build a simple command-line application that fetches real-time weather data from a public API. You will use reqwest to make HTTP requests, serde to parse the JSON response, and clap to accept city names from the terminal.
This is the kind of CLI I wish I had built earlier while learning Rust. It combines everything we have covered so far: arguments, HTTP requests, JSON parsing, and error handling. The full project fits in under 100 lines and is very practical.
What You Will Learn
- Accepting city name from the command line
- Making HTTP requests with reqwest
- Parsing JSON responses using serde
- Handling errors gracefully
- Formatting output for the user
Step 1: Project Setup
In Cargo.toml:
[dependencies]
clap = { version = "4.4", features = ["derive"] }
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Example:

Step 2: Create the Structs
Here is what the JSON response from the API looks like (Open-Meteo or wttr.in):
{
"current_weather": {
"temperature": 23.5,
"windspeed": 15.4
}
}
Define a struct to match it:
use serde::deserialize;
#[derive(Deserialize)]
struct WeatherResponse {
current_weather: WeatherData,
}
#[derive(Deserialize)]
struct WeatherData {
temperature: f64,
windspeed: f64,
}
Step 3: Accept City as Argument
Use clap to get a city name:
use clap::Parser;
#[derive(Parser)]
struct Args {
/// Name of the city
city: String,
}
Step 4: Make the HTTP Request
Use the free Open-Meteo API:
let url = format!(
"https://api.open-meteo.com/v1/forecast?latitude=28.61&longitude=77.20¤t_weather=true"
);
let response = reqwest::get(&url).await?;
let weather: WeatherResponse = response.json().await?;
Note: Replace coordinates with real ones based on the city (hardcoded or lookup).
Step 5: Show the Output
println!(
"Temperature: {}°C, Wind Speed: {} km/h",
weather.current_weather.temperature,
weather.current_weather.windspeed
);
Full Program
use clap::Parser;
use reqwest;
use serde::deserialize;
#[derive(Parser)]
struct Args {
city: String,
}
#[derive(Deserialize)]
struct WeatherResponse {
current_weather: WeatherData,
}
#[derive(Deserialize)]
struct WeatherData {
temperature: f64,
windspeed: f64,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
println!("Fetching weather for: {}", args.city);
// Hardcoded location for now (New Delhi)
let url = "https://api.open-meteo.com/v1/forecast?latitude=28.61&longitude=77.20¤t_weather=true";
let response = reqwest::get(url).await?;
let weather: WeatherResponse = response.json().await?;
println!(
"Temperature: {}°C, Wind Speed: {} km/h",
weather.current_weather.temperature,
weather.current_weather.windspeed
);
Ok(())
}
Output:

Exercise
Try modifying the app to:
- Look up city coordinates using another API (like geocoding)
- Handle network errors with custom messages
- Support saving results to a file
Summary
You just built a working CLI app in Rust that fetches real-time data from the internet. This project tied together everything from clap, reqwest, and serde, and showed how easy it is to build practical tools in Rust.
Rust Intermediate Concepts
- Generic Types in Functions and Structs
- Implementing Traits for Custom Behavior in Rust
- Trait Bounds and Constraints in Rust
- Lifetimes in Rust
- Using Closures (Anonymous Functions) in Rust
- The Iterator Trait and .next() in Rust
- Higher Order Iterator Methods: map, filter, and fold in Rust
- Using impl Trait for Simplicity in Rust
- Advanced Collections: HashSet and BTreeMap in Rust
- Custom Error Types and the Error Trait in Rust
- Option and Result Combinators in Rust
- Writing Unit Tests in Rust
- Integration Testing in Rust
- Logging in Rust with the log Crate
- Cargo Tips and Tricks for Rust Projects
- CLI Argument Parsing with Clap in Rust
- File I/O and File System Operations in Rust
- Running External Commands in Rust
- Make HTTP Requests in Rust with Reqwest
- JSON Serialization and Deserialization in Rust with Serde
- Building a Weather CLI in Rust
- Date and Time Handling in Rust with Chrono
- Using Regular Expressions in Rust with the regex Crate
- Memory Management in Rust
- Understanding Borrow Checker Errors in Rust
- Interacting with Databases in Rust
- Building a Todo List CLI in Rust with SQLite
- Concurrency in Rust