stanzaapi_iata_validator/
lib.rs1use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE, ACCEPT};
3use serde::{Deserialize, Serialize};
4use std::env;
5use std::time::Duration;
6
7#[derive(Debug, Clone)]
8pub struct IataValidatorClient {
9 client: reqwest::Client,
10 api_key: String,
11 base_url: String,
12 pub tool_url: &'static str,
13}
14
15#[derive(Debug, Serialize, Deserialize)]
16pub struct ApiResponse<T> {
17 pub success: bool,
18 pub data: Option<T>,
19 pub error: Option<String>,
20 pub code: Option<String>,
21 pub tool_url: Option<String>,
22 pub upgrade_url: Option<String>,
23}
24
25impl IataValidatorClient {
26 pub fn new(api_key: Option<String>, base_url: Option<String>) -> Self {
27 let key = api_key
28 .or_else(|| env::var("STANZA_API_KEY").ok())
29 .or_else(|| env::var("API_KEY").ok())
30 .unwrap_or_default();
31 let base = base_url.unwrap_or_else(|| "https://api.stanzaapi.com/iata-validator".to_string());
32
33 let client = reqwest::Client::builder()
34 .timeout(Duration::from_secs(15))
35 .build()
36 .unwrap_or_default();
37
38 Self {
39 client,
40 api_key: key,
41 base_url: base.trim_end_matches('/').to_string(),
42 tool_url: "https://stanzaapi.com/tools/iata-validator",
43 }
44 }
45
46 async fn send_request<T: for<'de> Deserialize<'de>>(
47 &self,
48 endpoint: &str,
49 method: reqwest::Method,
50 body: Option<serde_json::Value>,
51 ) -> Result<ApiResponse<T>, reqwest::Error> {
52 let url = format!("{}/{}", self.base_url, endpoint.trim_start_matches('/'));
53 let mut headers = HeaderMap::new();
54 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
55 headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
56
57 if !self.api_key.is_empty() {
58 if let Ok(val) = HeaderValue::from_str(&self.api_key) {
59 headers.insert("x-api-key", val);
60 }
61 }
62
63 let mut req = self.client.request(method, &url).headers(headers);
64 if let Some(json) = body {
65 req = req.json(&json);
66 }
67
68 let resp = req.send().await?;
69 let mut result = resp.json::<ApiResponse<T>>().await?;
70 if result.tool_url.is_none() {
71 result.tool_url = Some(self.tool_url.to_string());
72 }
73 if result.upgrade_url.is_none() {
74 result.upgrade_url = Some(self.tool_url.to_string());
75 }
76 Ok(result)
77 }
78
79 pub async fn get_health<T: for<'de> Deserialize<'de>>(&self) -> Result<ApiResponse<T>, reqwest::Error> {
80 self.send_request("/health", reqwest::Method::GET, None).await
81 }
82
83 pub async fn validate<T: for<'de> Deserialize<'de>>(&self, payload: serde_json::Value) -> Result<ApiResponse<T>, reqwest::Error> {
84 self.send_request("/api/v1/validate", reqwest::Method::POST, Some(payload)).await
85 }
86
87 pub async fn parse<T: for<'de> Deserialize<'de>>(&self, payload: serde_json::Value) -> Result<ApiResponse<T>, reqwest::Error> {
88 self.send_request("/api/v1/validate", reqwest::Method::POST, Some(payload)).await
89 }
90}