ironflow_engine/config/
http.rs1use ironflow_core::retry::RetryPolicy;
4use ironflow_core::trace_context::WorkflowTraceContext;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct HttpConfig {
19 pub method: String,
21 pub url: String,
23 pub headers: Vec<(String, String)>,
25 pub body: Option<Value>,
27 pub timeout_secs: Option<u64>,
29 #[serde(default)]
31 pub allow_failure: bool,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub retry: Option<RetryPolicy>,
35 #[serde(default, skip_serializing_if = "Option::is_none")]
37 pub trace_context: Option<WorkflowTraceContext>,
38}
39
40impl HttpConfig {
41 pub fn get(url: &str) -> Self {
52 Self::new("GET", url)
53 }
54
55 pub fn post(url: &str) -> Self {
57 Self::new("POST", url)
58 }
59
60 pub fn put(url: &str) -> Self {
62 Self::new("PUT", url)
63 }
64
65 pub fn patch(url: &str) -> Self {
67 Self::new("PATCH", url)
68 }
69
70 pub fn delete(url: &str) -> Self {
72 Self::new("DELETE", url)
73 }
74
75 fn new(method: &str, url: &str) -> Self {
76 Self {
77 method: method.to_string(),
78 url: url.to_string(),
79 headers: Vec::new(),
80 body: None,
81 timeout_secs: None,
82 allow_failure: false,
83 retry: None,
84 trace_context: None,
85 }
86 }
87
88 pub fn header(mut self, name: &str, value: &str) -> Self {
90 self.headers.push((name.to_string(), value.to_string()));
91 self
92 }
93
94 pub fn json(mut self, body: Value) -> Self {
96 self.body = Some(body);
97 self
98 }
99
100 pub fn timeout_secs(mut self, secs: u64) -> Self {
102 self.timeout_secs = Some(secs);
103 self
104 }
105
106 pub fn allow_failure(mut self) -> Self {
117 self.allow_failure = true;
118 self
119 }
120
121 pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
134 self.retry = Some(policy);
135 self
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use serde_json::json;
143
144 #[test]
145 fn methods() {
146 assert_eq!(HttpConfig::get("http://x").method, "GET");
147 assert_eq!(HttpConfig::post("http://x").method, "POST");
148 assert_eq!(HttpConfig::put("http://x").method, "PUT");
149 assert_eq!(HttpConfig::patch("http://x").method, "PATCH");
150 assert_eq!(HttpConfig::delete("http://x").method, "DELETE");
151 }
152
153 #[test]
154 fn builder() {
155 let config = HttpConfig::post("http://api.example.com")
156 .header("Authorization", "Bearer token")
157 .json(json!({"key": "value"}))
158 .timeout_secs(10);
159
160 assert_eq!(config.headers.len(), 1);
161 assert!(config.body.is_some());
162 assert_eq!(config.timeout_secs, Some(10));
163 }
164
165 #[test]
166 fn a_config_predating_retry_still_deserializes() {
167 let config: HttpConfig = serde_json::from_str(
168 r#"{"url":"http://x","method":"GET","headers":[],"body":null,"timeout_secs":null}"#,
169 )
170 .expect("deserialize");
171 assert!(config.retry.is_none());
172 }
173
174 #[test]
175 fn retry_policy_roundtrip() {
176 use ironflow_core::retry::RetryPolicy;
177
178 let config = HttpConfig::get("http://api").retry_policy(RetryPolicy::new(3));
179 let json = serde_json::to_string(&config).expect("serialize");
180 let back: HttpConfig = serde_json::from_str(&json).expect("deserialize");
181 assert_eq!(back.retry.as_ref().unwrap().max_retries(), 3);
182 }
183}