built-with-chatGPT/openwheatherAPI-rust.org

6.1 KiB

OpenWeatherMap Client

build a tiny Rust program that collects weather data for a collection of POI of mine and writes it into a SQLite database

initial prompt

please parse OpenWeatherAPI response in rust

Accidently I used not the full name which should bei openWeatherMap

Response:

  extern crate reqwest;
extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::error::Error;

#[derive(Deserialize, Debug)]
struct WeatherResponse {
    main: Main,
    weather: Vec<Weather>,
}

#[derive(Deserialize, Debug)]
struct Main {
    temp: f64,
    pressure: f64,
    humidity: f64,
    temp_min: f64,
    temp_max: f64,
}

#[derive(Deserialize, Debug)]
struct Weather {
    id: u32,
    main: String,
    description: String,
    icon: String,
}

fn get_weather(city: &str) -> Result<(), Box<dyn Error>> {
    let url = format!(
        "https://api.openweathermap.org/data/2.5/weather?q={}&appid={API_KEY}",
        city, API_KEY=API_KEY
    );

    let mut resp = reqwest::get(&url)?;
    let weather: WeatherResponse = resp.json()?;

    println!("Temperature: {}°F", weather.main.temp);
    println!("Pressure: {} hPa", weather.main.pressure);
    println!("Humidity: {}%", weather.main.humidity);
    println!("Minimum temperature: {}°F", weather.main.temp_min);
    println!("Maximum temperature: {}°F", weather.main.temp_max);
    for w in weather.weather {
        println!("{}: {}", w.main, w.description);
    }

    Ok(())
}

This example uses the reqwest crate to make an HTTP request to the OpenWeatherAPI and the serde and serde_json crates to parse the JSON response.

The WeatherResponse struct represents the top-level JSON object in the response, with fields for the main weather information and a list of weather conditions. The Main struct represents the main weather information, with fields for temperature, pressure, humidity, and minimum and maximum temperature. The Weather struct represents a single weather condition, with fields for the condition ID, main condition, description, and icon.

The get_weather function makes a request to the OpenWeatherAPI for the given city and parses the response into a WeatherResponse struct. It then prints out the main weather information and the list of weather conditions.

You'll need to replace API_KEY with your own API key, which you can get by signing up for a free account at https://home.openweathermap.org/users/sign_up.

See how it even shows me where to get and put the API key required for the HTTP request

Ask for Async and SQLITE

please use async and send the result to sqlite database

Response:

Sure! Here's an example of how you can use async and send the result to a SQLite database in Rust:

First, you'll need to add the following dependencies to your Cargo.toml file:

[dependencies]
async-std = { version = "1", features = ["attributes"] }
sqlx = { version = "0.4", features = ["macros"] }
  use async_std::task;
use sqlx::{query, query_as, Executor};

#[derive(Deserialize, Insertable)]
#[table_name = "weather"]
struct WeatherData {
    city: String,
    temperature: f64,
    pressure: f64,
    humidity: f64,
    temp_min: f64,
    temp_max: f64,
    main: String,
    description: String,
}

async fn get_weather_async(city: &str, db: &mut sqlx::SqliteConnection) -> Result<(), Box<dyn std::error::Error>> {
    let url = format!(
        "https://api.openweathermap.org/data/2.5/weather?q={}&appid={API_KEY}",
        city, API_KEY=API_KEY
    );

    let resp: WeatherResponse = reqwest::get(&url)
        .await?
        .json()
        .await?;

    let weather_data = WeatherData {
        city: city.to_string(),
        temperature: resp.main.temp,
        pressure: resp.main.pressure,
        humidity: resp.main.humidity,
        temp_min: resp.main.temp_min,
        temp_max: resp.main.temp_max,
        main: resp.weather[0].main,
        description: resp.weather[0].description,
    };

    query!(
        "INSERT INTO weather (city, temperature, pressure, humidity, temp_min, temp_max, main, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
        weather_data.city,
        weather_data.temperature,
        weather_data.pressure,
        weather_data.humidity,
        weather_data.temp_min,
        weather_data.temp_max,
        weather_data.main,
        weather_data.description
    )
    .execute(db)
    .await?;

    Ok(())
}

#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut db = sqlx::SqliteConnection::connect("sqlite://./weather.db").await?;

    task::spawn(async {
        get_weather_async("New York", &mut db).await.unwrap();
    });

    task::spawn(async {
        get_weather_async("London", &mut db).await.unwrap();
    });

    task::spawn(async {

The last part of the response is snipped here again. I assume, that the number of token for my free account is reached here. We can probably work around that by requesting more concise parts of the code.

I dont want to use the 'city' parameter

can I use lat,lon coordinates instead of the city parameter?

Response:

Yes, you can use latitude and longitude coordinates instead of the city parameter to get the weather information for a specific location from the OpenWeatherAPI.

To do this, you'll need to modify the API request URL to include the lat and lon parameters. For example:

  let url = format!(
    "https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={API_KEY}",
    lat=lat, lon=lon, API_KEY=API_KEY
);

Here, lat and lon are the latitude and longitude coordinates of the location you want to get the weather information for. Make sure to replace API_KEY with your own API key, which you can get by signing up for a free account at https://home.openweathermap.org/users/sign_up.

You can then use the modified URL to make the API request and parse the response as shown in the previous example.

I like how it refers to the previous output and tells me which part to update.