built-with-chatGPT/openwheatherAPI-rust.org

224 lines
6.1 KiB
Org Mode
Raw Normal View History

2022-12-22 19:20:31 +01:00
* 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
#+begin_quote
please parse OpenWeatherAPI response in rust
#+end_quote
Accidently I used not the full name which should bei *openWeatherMap*
Response:
#+begin_src rust
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(())
}
#+end_src
#+begin_quote
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.
#+end_quote
See how it even shows me where to get and put the API key required for the HTTP request
** Ask for Async and SQLITE
#+begin_quote
please use async and send the result to sqlite database
#+end_quote
Response:
#+begin_quote
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:
#+end_quote
#+begin_src toml
[dependencies]
async-std = { version = "1", features = ["attributes"] }
sqlx = { version = "0.4", features = ["macros"] }
#+end_src
#+begin_src rust
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 {
#+end_src
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
#+begin_quote
can I use lat,lon coordinates instead of the city parameter?
#+end_quote
Response:
#+begin_quote
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:
#+end_quote
#+begin_src rust
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
);
#+end_src
#+begin_quote
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.
#+end_quote
I like how it refers to the previous output and tells me which part to update.