weather_rs/
lib.rs

1use core::fmt;
2use std::str::FromStr;
3
4use color_eyre::{Report, Result};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub enum Unit {
10    Standard,
11    Metric,
12    Imperial,
13}
14
15impl fmt::Display for Unit {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        match self {
18            Unit::Standard => write!(f, "standard"),
19            Unit::Metric => write!(f, "metric"),
20            Unit::Imperial => write!(f, "imperial"),
21        }
22    }
23}
24
25impl FromStr for Unit {
26    type Err = Report;
27
28    fn from_str(s: &str) -> Result<Self, Self::Err> {
29        match s.to_lowercase().as_str() {
30            "metric" | "c" => Ok(Self::Metric),
31            "standard" | "k" => Ok(Self::Standard),
32            "imperial" | "f" => Ok(Self::Imperial),
33            _ => Err(Report::msg("Invalid unit")),
34        }
35    }
36}
37
38/// Retrieves and returns the weather data from the given url using the
39/// API key
40pub async fn get_data(
41    base_url: &str,
42    api_key: &str,
43    location: &str,
44    units: &Unit,
45) -> Result<(String, String)> {
46    let request_url = format!(
47        "{}?appid={}&q={}&units={}",
48        base_url, api_key, location, units
49    );
50    let response = reqwest::get(request_url).await?.text().await?;
51    let data: Value = serde_json::from_str(response.as_str())?;
52    let weather = &data["weather"][0]["description"];
53    let temperature = &data["main"]["temp"];
54    if weather.is_null() || temperature.is_null() {
55        eprintln!("Data for \"{}\" not found", location);
56        Err(Report::msg("Weather data could not be found"))
57    } else {
58        let temp_suffix = match units {
59            Unit::Standard => "⁰K",
60            Unit::Metric => "⁰C",
61            Unit::Imperial => "⁰F",
62        };
63        let mut temp = temperature.to_string();
64        temp.push_str(temp_suffix);
65        Ok((temp, weather.to_string()))
66    }
67}