weg_li_api 0.1.4

Making working with the weg.li API more convenient
Documentation
use url::Url;

use crate::types::{
    district::{District, DistrictJson},
    request::RetrySettings,
};

use super::{
    error::ApiError,
    request::{execute_request, RetryData, DEFAULT_RETRY_SETTINGS},
};

pub async fn get_district_from_wegli_api(
    api_url: &Url,
    api_token: &String,
    zip: &String,
    retry_settings: &Option<RetrySettings>,
) -> Result<District, ApiError> {
    let retry_data = RetryData {
        retry_count: 0,
        settings: match retry_settings {
            Some(settings) => settings.clone(),
            None => DEFAULT_RETRY_SETTINGS,
        },
    };
    let request_builder = reqwest::Client::new()
        .get(format!("{}{}{}", api_url, "districts/", zip))
        .header("X-API-KEY", api_token);

    let response = match execute_request(&request_builder, &Some(retry_data)).await {
        Err(error) => return Err(error),
        Ok(response) => response,
    };

    match response.json::<DistrictJson>().await {
        Err(error) => return Err(ApiError::Deserialize(error)),
        Ok(val) => match District::try_from(&val) {
            Err(error) => {
                return Err(ApiError::Conversion(format!(
                    "failed to convert '{:?}': {}",
                    &val, error
                )))
            }
            Ok(charge) => return Ok(charge),
        },
    };
}

pub async fn get_districts_from_wegli_api(
    api_url: &Url,
    api_token: &String,
    retry_settings: &Option<RetrySettings>,
) -> Result<Vec<District>, ApiError> {
    let retry_data = RetryData {
        retry_count: 0,
        settings: match retry_settings {
            Some(settings) => settings.clone(),
            None => DEFAULT_RETRY_SETTINGS,
        },
    };
    let request_builder = reqwest::Client::new()
        .get(format!("{}{}", api_url, "districts"))
        .header("X-API-KEY", api_token);

    let response = match execute_request(&request_builder, &Some(retry_data)).await {
        Err(error) => return Err(error),
        Ok(response) => response,
    };

    match response.json::<Vec<DistrictJson>>().await {
        Err(error) => return Err(ApiError::Deserialize(error)),
        Ok(val) => {
            let mut districts: Vec<District> = vec![];
            for item in val {
                match District::try_from(&item) {
                    Err(error) => {
                        return Err(ApiError::Conversion(format!(
                            "failed to convert '{:?}': {}",
                            &item, error
                        )))
                    }
                    Ok(district) => districts.push(district),
                }
            }
            return Ok(districts);
        }
    };
}

#[cfg(test)]
mod tests {

    use std::str::FromStr;

    use url::Url;

    use super::{get_district_from_wegli_api, get_districts_from_wegli_api};

    #[tokio::test]
    async fn test_get_district_from_wegli_api() {
        let mut server = mockito::Server::new_async().await;

        let mock = server
            .mock("GET", "/districts/91443")
            .with_status(200)
            .with_header("content-type", "application/json; charset=utf-8")
            .with_body(
                r#"
                {
                    "name": "Scheinfeld",
                    "zip": "91443",
                    "email": "info@vgem.scheinfeld.de",
                    "prefixes": [
                        "NEA",
                        "SEF",
                        "UFF"
                    ],
                    "latitude": 49.6653406,
                    "longitude": 10.462567,
                    "aliases": [],
                    "personal_email": false,
                    "created_at": "2024-03-13T04:43:59.602+01:00",
                    "updated_at": "2024-03-13T22:12:03.399+01:00"
                }"#,
            )
            .create_async()
            .await;

        let response = get_district_from_wegli_api(
            &Url::from_str(&server.url()).unwrap(),
            &"any_api_key".to_string(),
            &"91443".to_string(),
            &None,
        )
        .await
        .unwrap();
        assert_eq!(&response.latitude, &49.6653406);
        mock.assert();
    }

    #[tokio::test]
    async fn test_get_districtss_from_wegli_api() {
        let mut server = mockito::Server::new_async().await;

        let mock = server
            .mock("GET", "/districts")
            .with_status(200)
            .with_header("content-type", "application/json; charset=utf-8")
            .with_body(
                r#"
                [
                    {
                        "name": "Scheinfeld",
                        "zip": "91443",
                        "email": "info@vgem.scheinfeld.de",
                        "prefixes": [
                            "NEA",
                            "SEF",
                            "UFF"
                        ],
                        "latitude": 49.6653406,
                        "longitude": 10.462567,
                        "aliases": [],
                        "personal_email": false,
                        "created_at": "2024-03-13T04:43:59.602+01:00",
                        "updated_at": "2024-03-13T22:12:03.399+01:00"
                    },
                    {
                        "name": "Meinerzhagen",
                        "zip": "58540",
                        "email": "post@meinerzhagen.de",
                        "prefixes": [
                            "MK"
                        ],
                        "latitude": 51.1206595,
                        "longitude": 7.7331115,
                        "aliases": null,
                        "personal_email": false,
                        "created_at": "2019-09-24T14:56:35.624+02:00",
                        "updated_at": "2020-03-06T18:02:53.389+01:00"
                    }
                ]"#,
            )
            .create_async()
            .await;

        let response = get_districts_from_wegli_api(
            &Url::from_str(&server.url()).unwrap(),
            &"any_api_key".to_string(),
            &None,
        )
        .await
        .unwrap();
        assert_eq!(&response[0].zip, &"91443".to_string());
        mock.assert();
    }
}