Skip to content

feat(workflow): support nested dot-notation in webhook trigger fields (#4235) - #4262

Open
iroiro147 wants to merge 1 commit into
block:mainfrom
iroiro147:fix/4235-webhook-nested-fields
Open

feat(workflow): support nested dot-notation in webhook trigger fields (#4235)#4262
iroiro147 wants to merge 1 commit into
block:mainfrom
iroiro147:fix/4235-webhook-nested-fields

Conversation

@iroiro147

Copy link
Copy Markdown

What

Webhook-triggered workflows received only top-level JSON fields because nested objects were stringified into a single value. A CloudEvents-style body like

{"type":"workflow.failed","data":{"title":"Deploy","reason":"Timeout"}}

surfaced {{trigger.type}}"workflow.failed" but {{trigger.data.title}} was unreachable — data itself was the entire serialized JSON, unusable as a sub-template key. Senders had to duplicate useful fields at the top level just for Buzz.

Both webhook-population sites had the same flat-stringify pattern (bridge.rs /workflows HTTP endpoint, command_executor.rs message_posted trigger with JSON content). This PR introduces a shared flatten_webhook_fields helper in buzz-workflow::executor that recursively flattens nested JSON objects/arrays into dot-notation keys, and swaps both call sites to use it.

Behavior

Template Before After
{{trigger.data.title}} unresolved literal "Deploy"
{{trigger.data}} serialized JSON string serialized JSON string (unchanged)
{{trigger.data.meta.attempt}} unresolved "3"
{{trigger.items.0.name}} unresolved array index lookup
{{trigger.count}} (top-level scalar) "42" "42" (unchanged)

Objects and arrays are still stored under their prefix as serialized JSON, so consumers who want the whole envelope continue to work. Existing top-level templates are bit-for-bit identical.

Implementation

One new shared function flatten_webhook_fields(map: &serde_json::Map<String, serde_json::Value>) -> HashMap<String, String> in crates/buzz-workflow/src/executor.rs:

  • Recursively walks objects/arrays → data.title, items.0.nested
  • Stores serialized JSON at the parent prefix for compatibility
  • Scalar values stringified; strings kept as-is

Both former inline loops replaced with one call:

  • bridge.rs:1889 (HTTP /workflows/{id}/webhook)
  • command_executor.rs:919 (message_posted trigger parsing event.content as JSON)

Tests

Four new unit tests in crates/buzz-workflow/src/executor.rs:

  • flatten_nested_object_produces_dotted_keys — CloudEvents-style shape
  • flatten_scalar_types_convert_to_stringsnumber/bool/null
  • flatten_array_produces_indexed_dotted_keysitems.0 etc.
  • resolve_template_uses_nested_webhook_field — end-to-end substitution

cargo test -p buzz-workflow --lib157 passed, 0 failed (4 new + 153 existing).
cargo test -p buzz-relay --lib bridge59 passed, 0 failed.
cargo check -p buzz-workflow -p buzz-relay — clean.

Linked issue

Refs #4235

…block#4235)

Webhook-triggered workflows previously received only top-level JSON
fields — nested objects were stringified whole into a single value,
making `{{trigger.data.title}}` unusable when the sender posted
CloudEvents-style envelopes:

    {"type":"workflow.failed","data":{"title":"Deploy","reason":"Timeout"}}

The fix introduces `flatten_webhook_fields` in buzz-workflow (executor.rs):
a shared helper that recursively flattens nested JSON objects and arrays
into dot-notation keys (`data.title`, `items.0.nested`, etc.). Scalar
values are stringified; objects/arrays are kept at their prefix as
serialized JSON so existing templates like `{{trigger.data}}` still
resolve to the raw JSON for consumers who want the whole envelope.

Both webhook-population sites now use the shared helper:
- crates/buzz-relay/src/api/bridge.rs:1889 — HTTP `/workflows/{id}/webhook`
- crates/buzz-relay/src/handlers/command_executor.rs:919 — message_posted
  triggers parsing event.content as JSON

Behavior change:
- `{{trigger.data.title}}` → `"Deploy"` (was: literal template text)
- `{{trigger.data}}` → serialized JSON string (unchanged)
- `{{trigger.data.meta.attempt}}` → nested-scalar lookup (new)
- Array indexing: `{{trigger.items.0.name}}` (new)

Existing top-level fields preserved verbatim — no consumer should
observe a breaking change.

Regression tests in buzz-workflow (executor.rs):
- flatten_nested_object_produces_dotted_keys
- flatten_scalar_types_convert_to_strings
- flatten_array_produces_indexed_dotted_keys
- resolve_template_uses_nested_webhook_field (end-to-end template
  substitution over flattened context)

Verified:
- `cargo test -p buzz-workflow --lib` — 157 passed, 0 failed
- `cargo test -p buzz-relay --lib bridge` — 59 passed, 0 failed
- `cargo check -p buzz-workflow -p buzz-relay` — clean

Refs block#4235

Signed-off-by: Sarthak Singh <sarthak.singh@juspay.in>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant