use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum ApiProtocol {
#[default]
Query,
Json,
RestJson,
RestXml,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct PaginationConfig {
#[serde(default)]
pub input_token: Option<String>,
#[serde(default)]
pub output_token: Option<String>,
#[serde(default)]
pub max_results_param: Option<String>,
#[serde(default)]
pub max_results: Option<u32>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ApiConfig {
#[serde(default)]
pub protocol: ApiProtocol,
#[serde(default)]
pub service_name: Option<String>,
#[serde(default)]
pub action: Option<String>,
#[serde(default)]
pub method: Option<String>,
#[serde(default)]
pub path: Option<String>,
#[serde(default)]
pub response_root: Option<String>,
#[serde(default)]
pub items_path: Option<String>,
#[serde(default)]
pub static_params: HashMap<String, Value>,
#[serde(default)]
pub param_mapping: HashMap<String, String>,
#[serde(default)]
pub pagination: Option<PaginationConfig>,
#[serde(default)]
pub pre_hooks: Vec<String>,
#[serde(default)]
pub composite: bool,
#[serde(default)]
pub operations: Vec<CompositeOperation>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct CompositeOperation {
pub action: String,
#[serde(default)]
pub store_as: Option<String>,
#[serde(default)]
pub input: HashMap<String, Value>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct FieldMapping {
pub source: String,
#[serde(default)]
pub default: Option<String>,
#[serde(default)]
pub transform: Option<String>,
#[serde(default)]
pub array_item_path: Option<String>,
}
impl Default for FieldMapping {
fn default() -> Self {
Self {
source: String::new(),
default: Some("-".to_string()),
transform: None,
array_item_path: None,
}
}
}
#[derive(Debug, Clone)]
pub struct ParsedResponse {
pub items: Vec<Value>,
pub next_token: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ActionConfig {
pub action_id: String,
pub protocol: ApiProtocol,
#[serde(default)]
pub service_name: Option<String>,
#[serde(default)]
pub action: Option<String>,
#[serde(default)]
pub method: Option<String>,
#[serde(default)]
pub path: Option<String>,
#[serde(default)]
pub id_param: Option<String>,
#[serde(default)]
pub static_params: HashMap<String, Value>,
#[serde(default)]
pub body_template: Option<String>,
#[serde(default)]
pub special_handling: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DescribeConfig {
pub protocol: ApiProtocol,
#[serde(default)]
pub service_name: Option<String>,
#[serde(default)]
pub action: Option<String>,
#[serde(default)]
pub method: Option<String>,
#[serde(default)]
pub path: Option<String>,
#[serde(default)]
pub id_param: Option<String>,
#[serde(default)]
pub response_path: Option<String>,
#[serde(default)]
pub body_template: Option<String>,
#[serde(default)]
pub enrich_calls: Vec<EnrichCall>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct EnrichCall {
pub action: Option<String>,
pub path: Option<String>,
pub method: Option<String>,
pub result_field: String,
pub extract_path: Option<String>,
#[serde(default)]
pub default_value: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_protocol_deserialize() {
let json = r#""query""#;
let protocol: ApiProtocol = serde_json::from_str(json).unwrap();
assert_eq!(protocol, ApiProtocol::Query);
let json = r#""json""#;
let protocol: ApiProtocol = serde_json::from_str(json).unwrap();
assert_eq!(protocol, ApiProtocol::Json);
let json = r#""rest-json""#;
let protocol: ApiProtocol = serde_json::from_str(json).unwrap();
assert_eq!(protocol, ApiProtocol::RestJson);
let json = r#""rest-xml""#;
let protocol: ApiProtocol = serde_json::from_str(json).unwrap();
assert_eq!(protocol, ApiProtocol::RestXml);
}
#[test]
fn test_field_mapping_deserialize() {
let json = r#"{"source": "/instanceId"}"#;
let mapping: FieldMapping = serde_json::from_str(json).unwrap();
assert_eq!(mapping.source, "/instanceId");
assert_eq!(mapping.default, None);
let json = r#"{"source": "/ipAddress", "default": "-"}"#;
let mapping: FieldMapping = serde_json::from_str(json).unwrap();
assert_eq!(mapping.source, "/ipAddress");
assert_eq!(mapping.default, Some("-".to_string()));
}
#[test]
fn test_api_config_deserialize() {
let json = r#"{
"protocol": "query",
"action": "DescribeInstances",
"response_root": "/DescribeInstancesResponse/reservationSet"
}"#;
let config: ApiConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.protocol, ApiProtocol::Query);
assert_eq!(config.action, Some("DescribeInstances".to_string()));
}
}