forecaster 0.1.3

A simple weather forecaster that takes all the data from https://openweathermap.org/ and displays it in a nice way.
use crate::api_client::{APIClient, Get};
use crate::entities::forecast::Forecast;
use crate::entities::place::Place;
use crate::utils::config::{get_cached_value, read_config, update_cache_value};
use anyhow::Result;

pub async fn get_current_weather(args: &[String]) -> Result<()> {
    let config = read_config();

    let city_name = match args.get(1) {
        Some(city_name) => city_name.clone(),
        None => match config.default_town {
            None => {
                return Err(anyhow::anyhow!(
                    "No city was provided in arguments or set as default in config"
                ));
            }
            Some(default_town) => default_town,
        },
    };

    let place = match get_coords_from_city_name(&city_name).await {
        None => return Ok(()),
        Some(place) => place,
    };

    update_cache_value(place.name, place.lat, place.lon)?;

    let weather = get_weather((&place.lat, &place.lon)).await?;

    print_results(&city_name, &weather);

    Ok(())
}

async fn get_coords_from_city_name(city_name: &String) -> Option<Place> {
    if let Some((_, lat, lon)) = get_cached_value(city_name) {
        return Some(Place {
            name: city_name.clone(),
            lat,
            lon,
            country: "".to_string(),
            state: "".to_string(),
        });
    }

    let api_client = APIClient::new();

    let places = match api_client
        .get::<Vec<Place>>(format!(
            "https://api.openweathermap.org/geo/1.0/direct?q={city_name}&limit=1"
        ))
        .await
    {
        Ok(places) => places,
        Err(err) => {
            println!("{}", err);
            println!("Something is not OK with geo coding request");
            return None;
        }
    };

    if places.is_empty() {
        println!("No places found under such term");
        return None;
    };

    places.get(0).cloned()
}

async fn get_weather(coords: (&f32, &f32)) -> Result<Forecast> {
    let lat = coords.0;
    let lon = coords.1;

    let api_client = APIClient::new();

    let Ok(forecast) = api_client
        .get::<Forecast>(format!(
            "https://api.openweathermap.org/data/2.5/weather?units=metric&lat={lat}&lon={lon}"
        ))
        .await
    else {
        return Err(anyhow::anyhow!("Couldn't get weather"));
    };

    Ok(forecast)
}

fn print_results(city_name: &String, weather_data: &Forecast) {
    println!("City:        {}", city_name);
    println!("Temperature: {}", weather_data.main.temp);
    println!("Feels like:  {}", weather_data.main.feels_like);
    println!("Wind speed:  {}", weather_data.wind.speed);
    if let Some(rain) = &weather_data.rain {
        println!("Rain:        {}", rain.n1h);
    }
    println!("Clouds:      {}", weather_data.clouds.all);
}