From c32f09d0a303e13bedee77bb50a39490eb43bde0 Mon Sep 17 00:00:00 2001 From: Raphael Date: Sun, 31 May 2026 09:35:24 +0200 Subject: [PATCH 1/4] feat: new reworked http functions --- .../taurus-core/src/runtime/functions/http.rs | 171 ++---------------- 1 file changed, 13 insertions(+), 158 deletions(-) diff --git a/crates/taurus-core/src/runtime/functions/http.rs b/crates/taurus-core/src/runtime/functions/http.rs index d88e76f..50af453 100644 --- a/crates/taurus-core/src/runtime/functions/http.rs +++ b/crates/taurus-core/src/runtime/functions/http.rs @@ -19,9 +19,7 @@ use ureq::http; use ureq::{Body, RequestExt}; pub(crate) const FUNCTIONS: &[FunctionRegistration] = &[ - FunctionRegistration::eager("http::request::create", create_request, 4), FunctionRegistration::eager("http::request::send", send_request, 1), - FunctionRegistration::eager("http::response::create", create_response, 3), FunctionRegistration::eager("rest::control::respond", respond, 1), ]; @@ -34,81 +32,20 @@ fn respond( _ctx: &mut ValueStore, _run: &mut crate::handler::registry::ThunkRunner<'_>, ) -> Signal { - args!(args => struct_val: Struct); - - let fields = &struct_val.fields; - - let Some(headers_val) = fields.get("headers") else { - return Signal::Failure(RuntimeError::new( - "T-STD-00001", - "InvalidArgumentRuntimeError", - "Missing 'headers' field".to_string(), - )); - }; - - let Some(status_code_val) = fields.get("http_status_code") else { - return fail( - "InvalidArgumentRuntimeError", - "Missing 'http_status_code' field", - ); - }; - - let Some(payload_val) = fields.get("payload") else { - return Signal::Failure(RuntimeError::new( - "T-STD-00001", - "InvalidArgumentRuntimeError", - "Missing 'payload' field".to_string(), - )); - }; - - let Some(Kind::StructValue(_headers_struct)) = &headers_val.kind else { - return fail( - "InvalidArgumentRuntimeError", - "Expected 'headers' to be StructValue", - ); - }; - - let Some(Kind::NumberValue(_status_code_str)) = &status_code_val.kind else { - return Signal::Failure(RuntimeError::new( - "T-STD-00001", - "InvalidArgumentRuntimeError", - "Expected 'status_code' to be NumberValue".to_string(), - )); - }; - - let Some(_payload_kind) = &payload_val.kind else { - return Signal::Failure(RuntimeError::new( - "T-STD-00001", - "InvalidArgumentRuntimeError", - "Expected 'payload' to have a value".to_string(), - )); - }; - - // `Respond` is a control signal; the executor can still continue with `next` if present. - Signal::Respond(Value { - kind: Some(Kind::StructValue(struct_val.clone())), - }) -} - -fn create_request( - args: &[Argument], - _ctx: &mut ValueStore, - _run: &mut crate::handler::registry::ThunkRunner<'_>, -) -> Signal { - args!(args => http_method: String, headers: Struct, http_url: String, payload: Value); - let mut fields = std::collections::HashMap::new(); + args!(args => http_status_code: i64, headers: Struct, payload: Value); - fields.insert(String::from("http_method"), http_method.to_value()); - fields.insert(String::from("url"), http_url.to_value()); - fields.insert(String::from("payload"), payload.clone()); + let mut fields = HashMap::new(); + fields.insert("http_status_code".to_string(), http_status_code.to_value()); fields.insert( - String::from("headers"), + "headers".to_string(), Value { - kind: Some(Kind::StructValue(headers.clone())), + kind: Some(Kind::StructValue(headers)), }, ); + fields.insert("payload".to_string(), payload); - Signal::Success(Value { + // `Respond` is a control signal; the executor can still continue with `next` if present. + Signal::Respond(Value { kind: Some(Kind::StructValue(Struct { fields })), }) } @@ -118,31 +55,9 @@ fn send_request( _ctx: &mut ValueStore, _run: &mut crate::handler::registry::ThunkRunner<'_>, ) -> Signal { - args!(args => http_request: Struct); - - let method = match expect_struct_string_field(&http_request, "http_method") { - Ok(value) => value, - Err(signal) => return signal, - }; - let url = match expect_struct_string_field(&http_request, "url") { - Ok(value) => value, - Err(signal) => return signal, - }; - let headers_struct = match expect_struct_struct_field(&http_request, "headers") { - Ok(value) => value, - Err(signal) => return signal, - }; - let payload = match http_request.fields.get("payload") { - Some(value) => value.clone(), - None => { - return fail( - "InvalidArgumentRuntimeError", - "Missing 'payload' field in http_request", - ); - } - }; + args!(args => http_method: String, headers: Struct, http_url: String, payload: Value); - let mut headers = match encode_headers(&headers_struct) { + let mut headers = match encode_headers(&headers) { Ok(headers) => headers, Err(message) => return fail("InvalidArgumentRuntimeError", message), }; @@ -160,17 +75,17 @@ fn send_request( headers.insert("content-type".to_string(), default_content_type.to_string()); } - let http_method = match http::Method::from_bytes(method.as_bytes()) { + let http_method = match http::Method::from_bytes(http_method.as_bytes()) { Ok(value) => value, Err(_) => { return fail( "InvalidArgumentRuntimeError", - format!("Invalid HTTP method '{}'", method), + format!("Invalid HTTP method '{}'", http_method), ); } }; - let mut request_builder = http::Request::builder().method(http_method).uri(&url); + let mut request_builder = http::Request::builder().method(http_method).uri(&http_url); for (name, value) in &headers { request_builder = request_builder.header(name, value); } @@ -244,66 +159,6 @@ fn send_request( }) } -fn create_response( - args: &[Argument], - _ctx: &mut ValueStore, - _run: &mut crate::handler::registry::ThunkRunner<'_>, -) -> Signal { - args!(args => http_status_code: i64, headers: Struct, payload: Value); - let mut fields = std::collections::HashMap::new(); - - fields.insert( - String::from("http_status_code"), - http_status_code.to_value(), - ); - fields.insert(String::from("payload"), payload.clone()); - - fields.insert( - String::from("headers"), - Value { - kind: Some(Kind::StructValue(headers.clone())), - }, - ); - - Signal::Success(Value { - kind: Some(Kind::StructValue(Struct { fields })), - }) -} - -fn expect_struct_string_field(struct_val: &Struct, field: &str) -> Result { - let Some(value) = struct_val.fields.get(field) else { - return Err(fail( - "InvalidArgumentRuntimeError", - format!("Missing '{}' field in http_request", field), - )); - }; - - match &value.kind { - Some(Kind::StringValue(str_val)) => Ok(str_val.clone()), - _ => Err(fail( - "InvalidArgumentRuntimeError", - format!("Expected '{}' to be StringValue", field), - )), - } -} - -fn expect_struct_struct_field(struct_val: &Struct, field: &str) -> Result { - let Some(value) = struct_val.fields.get(field) else { - return Err(fail( - "InvalidArgumentRuntimeError", - format!("Missing '{}' field in http_request", field), - )); - }; - - match &value.kind { - Some(Kind::StructValue(struct_val)) => Ok(struct_val.clone()), - _ => Err(fail( - "InvalidArgumentRuntimeError", - format!("Expected '{}' to be StructValue", field), - )), - } -} - fn encode_headers(headers: &Struct) -> Result, String> { let mut out = HashMap::with_capacity(headers.fields.len()); for (name, value) in &headers.fields { From c88073258a6882cd0a04a9a95eaa4c1ea5d6cddd Mon Sep 17 00:00:00 2001 From: Raphael Date: Sun, 31 May 2026 09:38:07 +0200 Subject: [PATCH 2/4] feat: adjusted tests to new agrument signature of http functions --- .../taurus-core/src/runtime/functions/http.rs | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/crates/taurus-core/src/runtime/functions/http.rs b/crates/taurus-core/src/runtime/functions/http.rs index 50af453..357d4b3 100644 --- a/crates/taurus-core/src/runtime/functions/http.rs +++ b/crates/taurus-core/src/runtime/functions/http.rs @@ -565,26 +565,14 @@ mod tests { let request_headers = Struct { fields: HashMap::from([("x-bool".to_string(), true.to_value())]), }; - let request = Struct { - fields: HashMap::from([ - ("http_method".to_string(), string_value("POST")), - ( - "url".to_string(), - string_value(&format!("http://{}/echo?x=1", addr)), - ), - ( - "headers".to_string(), - Value { - kind: Some(Kind::StructValue(request_headers)), - }, - ), - ("payload".to_string(), request_payload), - ]), - }; - - let args = vec![Argument::Eval(Value { - kind: Some(Kind::StructValue(request)), - })]; + let args = vec![ + Argument::Eval(string_value("POST")), + Argument::Eval(Value { + kind: Some(Kind::StructValue(request_headers)), + }), + Argument::Eval(string_value(&format!("http://{}/echo?x=1", addr))), + Argument::Eval(request_payload), + ]; let mut ctx = ValueStore::default(); let mut run = |_: &crate::handler::argument::Thunk, _: &mut ValueStore| Signal::Stop; From f036da17cf22be0ef38aee635ccdcace74bcf690 Mon Sep 17 00:00:00 2001 From: Raphael Date: Sun, 31 May 2026 09:52:09 +0200 Subject: [PATCH 3/4] fix: correct arg count --- crates/taurus-core/src/runtime/functions/http.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/taurus-core/src/runtime/functions/http.rs b/crates/taurus-core/src/runtime/functions/http.rs index 357d4b3..3ee2b9b 100644 --- a/crates/taurus-core/src/runtime/functions/http.rs +++ b/crates/taurus-core/src/runtime/functions/http.rs @@ -19,8 +19,8 @@ use ureq::http; use ureq::{Body, RequestExt}; pub(crate) const FUNCTIONS: &[FunctionRegistration] = &[ - FunctionRegistration::eager("http::request::send", send_request, 1), - FunctionRegistration::eager("rest::control::respond", respond, 1), + FunctionRegistration::eager("http::request::send", send_request, 4), + FunctionRegistration::eager("rest::control::respond", respond, 3), ]; fn fail(category: &str, message: impl Into) -> Signal { From 34f4e0aa204c709894d89424b27820c2240f4411 Mon Sep 17 00:00:00 2001 From: Raphael Date: Sun, 31 May 2026 09:52:22 +0200 Subject: [PATCH 4/4] fix: removed dropped functions from tests --- crates/taurus-core/src/runtime/engine.rs | 14 ++++---------- flows/01_return_object.json | 21 ++------------------- 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/crates/taurus-core/src/runtime/engine.rs b/crates/taurus-core/src/runtime/engine.rs index 5c67a2e..9a388e8 100644 --- a/crates/taurus-core/src/runtime/engine.rs +++ b/crates/taurus-core/src/runtime/engine.rs @@ -754,9 +754,9 @@ mod tests { events.borrow_mut().push(emit_type); }; - let create_response_node = node( + let respond_node = node( 1, - "http::response::create", + "rest::control::respond", vec![ literal_param(100, "http_status_code", int_value(200)), literal_param(101, "headers", empty_struct_value()), @@ -764,14 +764,8 @@ mod tests { ], Some(2), ); - let respond_node = node( - 2, - "rest::control::respond", - vec![node_result_ref_param(200, "response", 1)], - Some(3), - ); let finish_node = node( - 3, + 2, "std::number::add", vec![ literal_param(300, "lhs", int_value(1)), @@ -782,7 +776,7 @@ mod tests { let (_signal, reason) = engine.execute_graph( 1, - vec![create_response_node, respond_node, finish_node], + vec![respond_node, finish_node], None, None, Some(&emitter), diff --git a/flows/01_return_object.json b/flows/01_return_object.json index c6e8290..2f9f86c 100644 --- a/flows/01_return_object.json +++ b/flows/01_return_object.json @@ -18,24 +18,8 @@ "node_functions": [ { "definition_source": "taurus", - "databaseId": "2", - "runtimeFunctionId": "rest::control::respond", - "parameters": [ - { - "databaseId": "4", - "runtimeParameterId": "http_response", - "value": { - "referenceValue": { - "nodeId": "1" - } - } - } - ] - }, - { "databaseId": "1", - "definition_source": "taurus", - "runtimeFunctionId": "http::response::create", + "runtimeFunctionId": "rest::control::respond", "parameters": [ { "databaseId": "1", @@ -72,8 +56,7 @@ } } } - ], - "nextNodeId": "2" + ] } ] }