use ironflow_core::retry::RetryPolicy;
use ironflow_core::trace_context::WorkflowTraceContext;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HttpConfig {
pub method: String,
pub url: String,
pub headers: Vec<(String, String)>,
pub body: Option<Value>,
pub timeout_secs: Option<u64>,
#[serde(default)]
pub allow_failure: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub retry: Option<RetryPolicy>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trace_context: Option<WorkflowTraceContext>,
}
impl HttpConfig {
pub fn get(url: &str) -> Self {
Self::new("GET", url)
}
pub fn post(url: &str) -> Self {
Self::new("POST", url)
}
pub fn put(url: &str) -> Self {
Self::new("PUT", url)
}
pub fn patch(url: &str) -> Self {
Self::new("PATCH", url)
}
pub fn delete(url: &str) -> Self {
Self::new("DELETE", url)
}
fn new(method: &str, url: &str) -> Self {
Self {
method: method.to_string(),
url: url.to_string(),
headers: Vec::new(),
body: None,
timeout_secs: None,
allow_failure: false,
retry: None,
trace_context: None,
}
}
pub fn header(mut self, name: &str, value: &str) -> Self {
self.headers.push((name.to_string(), value.to_string()));
self
}
pub fn json(mut self, body: Value) -> Self {
self.body = Some(body);
self
}
pub fn timeout_secs(mut self, secs: u64) -> Self {
self.timeout_secs = Some(secs);
self
}
pub fn allow_failure(mut self) -> Self {
self.allow_failure = true;
self
}
pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
self.retry = Some(policy);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn methods() {
assert_eq!(HttpConfig::get("http://x").method, "GET");
assert_eq!(HttpConfig::post("http://x").method, "POST");
assert_eq!(HttpConfig::put("http://x").method, "PUT");
assert_eq!(HttpConfig::patch("http://x").method, "PATCH");
assert_eq!(HttpConfig::delete("http://x").method, "DELETE");
}
#[test]
fn builder() {
let config = HttpConfig::post("http://api.example.com")
.header("Authorization", "Bearer token")
.json(json!({"key": "value"}))
.timeout_secs(10);
assert_eq!(config.headers.len(), 1);
assert!(config.body.is_some());
assert_eq!(config.timeout_secs, Some(10));
}
#[test]
fn a_config_predating_retry_still_deserializes() {
let config: HttpConfig = serde_json::from_str(
r#"{"url":"http://x","method":"GET","headers":[],"body":null,"timeout_secs":null}"#,
)
.expect("deserialize");
assert!(config.retry.is_none());
}
#[test]
fn retry_policy_roundtrip() {
use ironflow_core::retry::RetryPolicy;
let config = HttpConfig::get("http://api").retry_policy(RetryPolicy::new(3));
let json = serde_json::to_string(&config).expect("serialize");
let back: HttpConfig = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back.retry.as_ref().unwrap().max_retries(), 3);
}
}