Add documentation to query.rs
- Documentation comments - Tests
This commit is contained in:
parent
66f04c5cc9
commit
808325c534
@ -1,11 +1,45 @@
|
|||||||
|
//! Query construction for `OpenWeatherMap` API v2.5
|
||||||
|
//!
|
||||||
|
//! Provides types and utilities for building request URLs for the
|
||||||
|
//! `/weather` and `/forecast` endpoints.
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! use owm_api25::query::{QueryParams, Units, WEATHER_URL};
|
||||||
|
//!
|
||||||
|
//! let query = QueryParams {
|
||||||
|
//! api_key: "MY_KEY".into(),
|
||||||
|
//! city_name: Some("London".into()),
|
||||||
|
//! ..Default::default()
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! let url = query.weather_url().unwrap();
|
||||||
|
//! assert!(url.contains("q=London"));
|
||||||
|
//! ```
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Base URLs for `OpenWeatherMap` API v2.5
|
||||||
pub const BASE_URL: &str = "https://api.openweathermap.org/data/2.5";
|
pub const BASE_URL: &str = "https://api.openweathermap.org/data/2.5";
|
||||||
pub const WEATHER_URL: &str = "https://api.openweathermap.org/data/2.5/weather";
|
pub const WEATHER_URL: &str = "https://api.openweathermap.org/data/2.5/weather";
|
||||||
pub const FORECAST_URL: &str = "https://api.openweathermap.org/data/2.5/forecast";
|
pub const FORECAST_URL: &str = "https://api.openweathermap.org/data/2.5/forecast";
|
||||||
|
|
||||||
/// Units of measurement for temperature and wind speed
|
/// Units of measurement for temperature and wind speed.
|
||||||
#[derive(Debug)]
|
///
|
||||||
|
/// - **Standard**: Kelvin (temperature), m/s (wind)
|
||||||
|
/// - **Metric**: Celsius, m/s
|
||||||
|
/// - **Imperial**: Fahrenheit, miles/hour
|
||||||
|
///
|
||||||
|
/// See: <https://openweathermap.org/current#data>
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use owm_api25::query::Units;
|
||||||
|
/// assert_eq!(Units::Metric.to_string(), "metric");
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Units {
|
pub enum Units {
|
||||||
Standard,
|
Standard,
|
||||||
Metric,
|
Metric,
|
||||||
@ -22,16 +56,43 @@ impl fmt::Display for Units {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query parameters for `OpenWeatherMap` Free API v2.5 endpoints
|
/// Query parameters for `OpenWeatherMap` API.
|
||||||
#[derive(Debug)]
|
///
|
||||||
|
/// **Note:** One of `city_id`, `city_name`, `(lat, lon)` pair, or `zip` **must** be provided,
|
||||||
|
/// otherwise URL building will fail.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct QueryParams {
|
pub struct QueryParams {
|
||||||
|
/// Your `OpenWeatherMap` API key
|
||||||
pub api_key: String,
|
pub api_key: String,
|
||||||
|
|
||||||
|
/// City ID (optional)
|
||||||
|
///
|
||||||
|
/// You can make an API call by city ID to get an unambiguous result for your city.
|
||||||
|
/// The list of city IDs (`city.list.json.gz`) can be downloaded [here](http://bulk.openweathermap.org/sample/).
|
||||||
pub city_id: Option<String>,
|
pub city_id: Option<String>,
|
||||||
|
|
||||||
|
/// City name (optional)
|
||||||
|
///
|
||||||
|
/// You can call by city name, or city name + state code + country code.
|
||||||
|
/// Searching by state is only available for locations in the USA.
|
||||||
|
/// See: <https://openweathermap.org/current#name>
|
||||||
pub city_name: Option<String>,
|
pub city_name: Option<String>,
|
||||||
|
|
||||||
|
/// Latitude (optional, must be used with `lon`)
|
||||||
pub lat: Option<f32>,
|
pub lat: Option<f32>,
|
||||||
|
|
||||||
|
/// Longitude (optional, must be used with `lat`)
|
||||||
pub lon: Option<f32>,
|
pub lon: Option<f32>,
|
||||||
|
|
||||||
|
/// Zip code (optional)
|
||||||
|
///
|
||||||
|
/// Format: `"94040,us"`. If the country code is not specified, it defaults to USA.
|
||||||
pub zip: Option<String>,
|
pub zip: Option<String>,
|
||||||
|
|
||||||
|
/// Units for temperature and wind (default `"Standard"`)
|
||||||
pub units: Units,
|
pub units: Units,
|
||||||
|
|
||||||
|
/// Language code for descriptions (default `"en"`)
|
||||||
pub lang: String,
|
pub lang: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +102,23 @@ impl QueryParams {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an `Err` if no valid location is specified
|
/// Returns an `Err` if no valid location is specified
|
||||||
/// (e.g., `city_id`, `city_name`, `lat`/`lon`, or `zip` are all `None`).
|
/// (`city_id`, `city_name`, `lat`/`lon`, or `zip` are all None).
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use owm_api25::query::{QueryParams, Units, WEATHER_URL};
|
||||||
|
///
|
||||||
|
/// let query = QueryParams {
|
||||||
|
/// api_key: "MY_API_KEY".to_string(),
|
||||||
|
/// city_name: Some("London".to_string()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let url = query.weather_url().unwrap();
|
||||||
|
/// assert!(url.contains("q=London"));
|
||||||
|
/// assert!(url.contains("appid=MY_API_KEY"));
|
||||||
|
/// ```
|
||||||
pub fn weather_url(&self) -> Result<String, String> {
|
pub fn weather_url(&self) -> Result<String, String> {
|
||||||
self.build_url(WEATHER_URL)
|
self.build_url(WEATHER_URL)
|
||||||
}
|
}
|
||||||
@ -50,12 +127,17 @@ impl QueryParams {
|
|||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an `Err` if no valid location is specified
|
/// Returns an `Err` if no valid location is specified.
|
||||||
/// (e.g., `city_id`, `city_name`, `lat`/`lon`, or `zip` are all `None`).
|
/// See `weather_url`.
|
||||||
pub fn forecast_url(&self) -> Result<String, String> {
|
pub fn forecast_url(&self) -> Result<String, String> {
|
||||||
self.build_url(FORECAST_URL)
|
self.build_url(FORECAST_URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Internal helper to build query URL.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an `Err` if no valid location is specified (`city_id`, `city_name`, `lat`/`lon`, or `zip`).
|
||||||
fn build_url(&self, base: &str) -> Result<String, String> {
|
fn build_url(&self, base: &str) -> Result<String, String> {
|
||||||
let mut params = vec![
|
let mut params = vec![
|
||||||
format!("appid={}", self.api_key),
|
format!("appid={}", self.api_key),
|
||||||
@ -79,3 +161,93 @@ impl QueryParams {
|
|||||||
Ok(format!("{base}?{}", params.join("&")))
|
Ok(format!("{base}?{}", params.join("&")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Default values for query parameters
|
||||||
|
impl Default for QueryParams {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
api_key: String::new(),
|
||||||
|
city_id: None,
|
||||||
|
city_name: None,
|
||||||
|
lat: None,
|
||||||
|
lon: None,
|
||||||
|
zip: None,
|
||||||
|
units: Units::Standard,
|
||||||
|
lang: "en".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_weather_url_city_name() {
|
||||||
|
let query = QueryParams {
|
||||||
|
api_key: "KEY".into(),
|
||||||
|
city_name: Some("Paris".into()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let url = query.weather_url().unwrap();
|
||||||
|
assert!(url.contains("q=Paris"));
|
||||||
|
assert!(url.contains("appid=KEY"));
|
||||||
|
assert!(url.starts_with(WEATHER_URL));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_weather_url_city_id() {
|
||||||
|
let query = QueryParams {
|
||||||
|
api_key: "KEY".into(),
|
||||||
|
city_id: Some("123".into()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let url = query.weather_url().unwrap();
|
||||||
|
assert!(url.contains("id=123"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_weather_url_lat_lon() {
|
||||||
|
let query = QueryParams {
|
||||||
|
api_key: "KEY".into(),
|
||||||
|
lat: Some(10.0),
|
||||||
|
lon: Some(20.0),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let url = query.weather_url().unwrap();
|
||||||
|
assert!(url.contains("lat=10") && url.contains("lon=20"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_weather_url_zip() {
|
||||||
|
let query = QueryParams {
|
||||||
|
api_key: "KEY".into(),
|
||||||
|
zip: Some("94040,us".into()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let url = query.weather_url().unwrap();
|
||||||
|
assert!(url.contains("zip=94040,us"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_weather_url_error() {
|
||||||
|
let query = QueryParams {
|
||||||
|
api_key: "KEY".into(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
assert!(query.weather_url().is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_forecast_url() {
|
||||||
|
let query = QueryParams {
|
||||||
|
api_key: "KEY".into(),
|
||||||
|
city_name: Some("Berlin".into()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let url = query.forecast_url().unwrap();
|
||||||
|
assert!(url.contains("q=Berlin"));
|
||||||
|
assert!(url.starts_with(FORECAST_URL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user