use axum::{extract::State, Json};
use std::sync::Arc;
use std::time::Instant;
use tracing::{debug, info};
use crate::logging::generate_request_id;
use crate::state::AppState;
pub async fn metadata_handler(State(state): State<Arc<AppState>>) -> Json<serde_json::Value> {
let request_id = generate_request_id();
let start_time = Instant::now();
debug!(
endpoint = "/metadata",
request_id = %request_id,
"Processing metadata request"
);
let response = serde_json::json!({
"global_attributes": state.metadata.global_attributes,
"dimensions": state.metadata.dimensions,
"variables": state.metadata.variables,
"coordinates": state.metadata.coordinates,
});
let duration = start_time.elapsed();
info!(
endpoint = "/metadata",
request_id = %request_id,
duration_us = duration.as_micros() as u64,
variable_count = state.metadata.variables.len(),
dimension_count = state.metadata.dimensions.len(),
"Metadata request successful"
);
Json(response)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::Config;
use crate::state::{AttributeValue, Dimension, Metadata, Variable};
use std::collections::HashMap;
#[test]
fn test_metadata_handler() {
let config = Config::default();
let mut dimensions = HashMap::new();
dimensions.insert(
"lat".to_string(),
Dimension {
name: "lat".to_string(),
size: 180,
is_unlimited: false,
},
);
dimensions.insert(
"lon".to_string(),
Dimension {
name: "lon".to_string(),
size: 360,
is_unlimited: false,
},
);
let mut variables = HashMap::new();
let mut var_attributes = HashMap::new();
var_attributes.insert("units".to_string(), AttributeValue::Text("K".to_string()));
variables.insert(
"temperature".to_string(),
Variable {
name: "temperature".to_string(),
dimensions: vec!["lat".to_string(), "lon".to_string()],
shape: vec![180, 360],
attributes: var_attributes,
dtype: "f32".to_string(),
},
);
let mut coordinates = HashMap::new();
coordinates.insert("lat".to_string(), vec![-90.0, 90.0]); coordinates.insert("lon".to_string(), vec![-180.0, 180.0]);
let metadata = Metadata {
global_attributes: HashMap::new(),
dimensions,
variables,
coordinates,
};
let data = HashMap::new();
let state = Arc::new(AppState::new(config, metadata, data));
let expected = serde_json::json!({
"global_attributes": state.metadata.global_attributes,
"dimensions": state.metadata.dimensions,
"variables": state.metadata.variables,
"coordinates": state.metadata.coordinates,
});
let response = Json(expected.clone());
let json = response.0;
assert!(json.get("dimensions").is_some());
assert!(json.get("variables").is_some());
assert!(json.get("coordinates").is_some());
assert!(json.get("global_attributes").is_some());
let vars = json.get("variables").unwrap();
assert!(vars.get("temperature").is_some());
let dims = json.get("dimensions").unwrap();
assert!(dims.get("lat").is_some());
assert!(dims.get("lon").is_some());
let coords = json.get("coordinates").unwrap().as_object().unwrap();
assert!(coords.contains_key("lat"));
assert!(coords.contains_key("lon"));
let lat_coords = coords.get("lat").unwrap().as_array().unwrap();
let lon_coords = coords.get("lon").unwrap().as_array().unwrap();
assert_eq!(
lat_coords,
&[serde_json::json!(-90.0), serde_json::json!(90.0)]
);
assert_eq!(
lon_coords,
&[serde_json::json!(-180.0), serde_json::json!(180.0)]
);
}
}