Skip to content

feat(dashboard): add raw JSON body mode to HTTP request step#10638

Open
FredRMonizze wants to merge 8 commits intonovuhq:nextfrom
FredRMonizze:feat/http-request-raw-json-body
Open

feat(dashboard): add raw JSON body mode to HTTP request step#10638
FredRMonizze wants to merge 8 commits intonovuhq:nextfrom
FredRMonizze:feat/http-request-raw-json-body

Conversation

@FredRMonizze
Copy link
Copy Markdown

@FredRMonizze FredRMonizze commented Apr 10, 2026

Summary

The HTTP Request action step currently only supports flat key-value pairs for the request body, making it impossible to send nested JSON objects required by many third-party APIs (e.g. CM Telecom Voice API which expects a voice: { language, gender, ... } object).

This PR adds a toggle between Key-Value and Raw JSON modes in the HTTP Request step, allowing users to paste/type a full JSON body with nested objects, arrays, and LiquidJS variables.

Related issue: #8784

Why

When integrating with APIs that expect nested JSON bodies, users currently have no way to send something like:

```json
{
"callee": "+32...",
"voice": {
"language": "fr",
"gender": "Male"
}
}
```

Workarounds tried (all failed):

  • `voice.language` as flat key → sent as literal `"voice.language"` key
  • `voice[language]` notation → same issue
  • Pasting JSON as a single value → string-escaped by Novu

Changes

Schema & Types

  • Added `bodyMode` (`'key-value' | 'raw'`, default `'key-value'`) and `rawBody` fields to the HTTP request control schema
  • Added `DESTINATION_BODY_MODE` and `DESTINATION_RAW_BODY` to `UiComponentEnum`
  • Updated `HttpRequestControlDto` with the new optional fields

Frontend (Dashboard)

  • New `RawBodyEditor` component with multiline textarea and LiquidJS variable support
  • Toggle between Key-Value and Raw JSON modes in the HTTP Request editor
  • Live JSON validation with inline error message (skipped when value contains `{{...}}` variables)
  • Confirmation prompt when switching back to Key-Value mode with existing raw JSON content
  • Updated `CurlDisplay` and `buildRawCurlString` to render raw body in the curl preview

Backend

  • New `parseRawBody()` utility that parses and validates raw JSON strings
  • Updated `ExecuteHttpRequestStep` usecase to use `parseRawBody` when `bodyMode === 'raw'`
  • Updated `TestHttpEndpoint` usecase to support raw body mode in the test feature
  • Updated `PreviewUsecase` for HMAC signature preview consistency

Tests

  • Added unit tests for `parseRawBody`, `toBodyRecord`, and `toHeadersRecord`

Backward compatibility

  • `bodyMode` defaults to `'key-value'` → existing workflows are unaffected
  • `rawBody` is optional → no migration needed
  • Field validation skips raw body when in key-value mode and vice versa

Test plan

  • Existing key-value mode still works as before
  • Switching to Raw JSON shows a multiline editor
  • Nested JSON objects are sent correctly to the target API (verified with CM Telecom Voice API)
  • LiquidJS variables (`{{payload.x}}`, `{{subscriber.x}}`) are resolved in raw body
  • Invalid JSON shows an inline error and prevents form save
  • Curl preview reflects the raw body content
  • Test endpoint works in raw mode
  • Switching back to Key-Value mode prompts for confirmation if raw body is non-empty
  • Unit tests for `parseRawBody` pass

Note

Medium Risk
Adds a new raw JSON body path that is parsed/validated and used for request signing/sending; invalid JSON or unexpected body types can cause runtime failures in HTTP request execution/testing/preview. Defaults preserve existing behavior, but this touches both dashboard UX and worker/api execution paths.

Overview
Adds support for sending HTTP Request step bodies as raw JSON in addition to the existing key-value pairs.

Updates shared schema/DTOs to include bodyMode and rawBody, adds a dashboard RawBodyEditor with JSON validation and a mode toggle (with confirmation when switching back), and updates cURL previews/copy to reflect raw bodies.

On the backend/worker, introduces parseRawBody and wires it into HTTP request execution, test endpoint, and preview signature generation so raw JSON is parsed as an object before signing/sending; includes unit tests for the new parsing utility.

Reviewed by Cursor Bugbot for commit 15f7166. Configure here.

What changed

Added a Raw JSON body mode to the HTTP Request action so users can enter nested JSON objects, arrays, and LiquidJS variables as the request body. The UI now offers a Key-Value ↔ Raw toggle and a multiline RawBodyEditor with live JSON validation (skipped when LiquidJS templates are present), draft behavior to avoid publishing invalid/whitespace-only bodies, and a confirmation when switching back to key-value. Backend and worker code parse and validate raw JSON (objects or arrays), return clear errors on parse failure, and ensure HMAC signature previews and curl/test flows reflect raw payloads.

Affected areas

api: Test endpoint use case reads bodyMode/rawBody and uses parseRawBody() for raw mode, returning 400 with a descriptive error and omitting the body in resolvedRequest on parse failure.
dashboard (react): Adds RawBodyEditor, body-mode toggle, draft/validation behavior, and threads rawBody/bodyMode into curl, console, and preview components so previews and generated curl include raw payloads.
worker: ExecuteHttpRequestStep uses parseRawBody() when bodyMode === 'raw', records parse failures to execution details, and fails the step safely while honoring continueOnFailure.
application-generic: Adds parseRawBody(), extends HttpRequestControlDto with bodyMode and rawBody, updates shouldIncludeBody and preview signature generation to support raw mode (objects or arrays).
shared: Adds bodyMode/rawBody to HTTP request control and UI schema and new UiComponentEnum entries DESTINATION_BODY_MODE and DESTINATION_RAW_BODY.
tests: New unit tests for parseRawBody (including top-level arrays), toBodyRecord, and toHeadersRecord; additional manual/preview checks described in the PR test plan.

Key technical decisions

  • Default bodyMode is 'key-value' for backward compatibility.
  • parseRawBody() accepts and returns either a JSON object or array and rejects non-object/array JSON (e.g., strings/null) with a specific error.
  • Raw-body validation/parsing is skipped when the content contains LiquidJS variables ({{...}}) to allow templated payloads.
  • Curl preview uses shell-escaping for single quotes and, in raw mode, emits only the rawBody to match backend behavior.

Testing

Added unit tests for parsing and conversions; manual/preview testing covers editor validation, mode-switch confirmation, nested JSON/array sending, LiquidJS resolution in previews, curl/test endpoint raw behavior, and HMAC signature consistency.

FredRMonizze and others added 2 commits April 9, 2026 09:23
The HTTP Request action step only supported flat key-value pairs for the
request body, making it impossible to send nested JSON objects required
by many third-party APIs (e.g. CM Telecom Voice API).

This adds a toggle between "Key-Value" and "Raw JSON" modes:
- New `bodyMode` field ("key-value" | "raw") with backward-compatible default
- New `rawBody` string field for raw JSON input
- Frontend toggle in the HTTP request editor
- New `RawBodyEditor` component with multiline input and variable support
- Backend `parseRawBody()` function to deserialize raw JSON
- Updated curl preview to reflect raw body mode
- Unit tests for parseRawBody and existing utils

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update test-http-endpoint usecase to support rawBody mode (was always
  using key-value pairs, breaking the test feature in raw mode)
- Update CurlDisplay component to render raw body when bodyMode is 'raw'
- Add live JSON validation in RawBodyEditor with error message display
- Skip validation when value contains LiquidJS variables ({{...}})
- Only persist raw body to form when JSON is valid (prevents broken state)
- Add confirmation prompt when switching back to key-value mode with
  existing raw JSON content (prevents accidental data loss)
- Use spans with role=button instead of <button> elements to fix
  invalid HTML nesting (button inside button warning)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@netlify
Copy link
Copy Markdown

netlify bot commented Apr 10, 2026

👷 Deploy request for dashboard-v2-novu-staging pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 75cb9c9

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a "raw" JSON body mode for HTTP workflow steps across UI, schemas/DTOs, curl preview, parsing utilities and tests, and backend handling in test and execution use cases. (23 words)

Changes

Cohort / File(s) Summary
Schema & DTOs
libs/application-generic/src/dtos/workflow/controls/http-request-control.dto.ts, packages/shared/src/consts/providers/channels/http-request.ts, packages/shared/src/dto/workflows/step.dto.ts
Added `bodyMode?: 'key-value'
Frontend — Editor & UI
apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-editor.tsx, apps/dashboard/src/components/workflow-editor/steps/http-request/raw-body-editor.tsx, apps/dashboard/src/components/workflow-editor/steps/component-utils.tsx
Introduced RawBodyEditor, watched bodyMode/rawBody, toggle UI and confirmation when switching modes discarding content, conditional rendering between key-value editor and raw editor, and wired component factory to render new components.
Frontend — Preview / Console / cURL
apps/dashboard/src/components/workflow-editor/steps/http-request/configure-http-request-step-preview.tsx, apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-console-preview.tsx, apps/dashboard/src/components/workflow-editor/steps/http-request/curl-display.tsx, apps/dashboard/src/components/workflow-editor/steps/http-request/curl-utils.ts
Threaded rawBody and bodyMode through preview/console; extended CurlDisplay props and buildRawCurlString to render --data using raw JSON when bodyMode === 'raw'; added escapeShellSingleQuoted and escaped URL/header/body/signature values in generated curl.
Backend — Test & Execution
apps/api/src/app/workflows-v2/usecases/test-http-endpoint/test-http-endpoint.usecase.ts, apps/worker/src/app/workflow/usecases/send-message/execute-http-request-step.usecase.ts, libs/application-generic/src/usecases/preview/preview.usecase.ts
When bodyMode === 'raw' parse rawBody via parseRawBody and use parsed value for request body and signature; test endpoint returns 400 on parse errors, worker logs/fails execution on parse errors; fallback to key-value parsing otherwise.
Utilities & Tests
libs/application-generic/src/services/http-client/http-request.utils.ts, libs/application-generic/src/services/http-client/http-request.utils.spec.ts
Added parseRawBody(raw: string) (validate parsed JSON is object/array), updated shouldIncludeBody to accept arrays, and added unit tests covering parsing and error cases.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(66,133,244,0.5)
    participant Editor
    end
    rect rgba(15,157,88,0.5)
    participant API
    end
    rect rgba(219,68,55,0.5)
    participant Worker
    end
    rect rgba(244,180,0,0.5)
    participant External
    end

    Editor->>Editor: User edits step (bodyMode + bodyPairs or rawBody)
    Editor->>API: Save step (bodyMode, rawBody / body pairs)
    API->>Worker: Trigger send (compiled step with bodyMode/rawBody)
    alt bodyMode == "raw"
        Worker->>Worker: parseRawBody(rawBody)
        Worker->>Worker: buildNovuSignatureHeader(parsedBody)
    else key-value
        Worker->>Worker: toBodyRecord(bodyPairs)
        Worker->>Worker: buildNovuSignatureHeader(bodyObject)
    end
    Worker->>External: Send HTTP request with computed body & headers
    External->>Worker: Response
    Worker->>API: Execution result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • djabarovgeorge
  • scopsy
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows Conventional Commits format with valid type (feat), valid scope (dashboard), and a clear, descriptive, lowercase imperative description of the feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@FredRMonizze FredRMonizze changed the title feat(http-request): add raw JSON body mode to HTTP request step feat(dashboard): add raw JSON body mode to HTTP request step Apr 10, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
libs/application-generic/src/services/http-client/http-request.utils.ts (1)

21-28: Add blank line before return statement.

Per coding guidelines, include a blank line before every return statement.

✏️ Suggested fix
 export function parseRawBody(raw: string): Record<string, unknown> {
   const parsed = JSON.parse(raw);
   if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
     throw new Error('Raw body must be a JSON object');
   }
+
   return parsed as Record<string, unknown>;
 }

As per coding guidelines: "Include a blank line before every return statement".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@libs/application-generic/src/services/http-client/http-request.utils.ts`
around lines 21 - 28, In parseRawBody, add a blank line immediately before the
final return statement in the function parseRawBody to follow the coding
guideline requiring a blank line before every return; keep the function logic
unchanged and only insert the empty line above the return parsed as
Record<string, unknown>.
apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-console-preview.tsx (1)

509-514: Consider including rawBody and bodyMode in controlsKey to reset test results when body mode changes.

The controlsKey is used to detect control value changes and reset test results. However, it doesn't include rawBody or bodyMode, so switching between body modes or editing raw body content won't trigger a reset of stale test results.

✏️ Suggested fix
   const controlsKey = JSON.stringify({
     url: controlValues?.url,
     method: controlValues?.method,
     headers: controlValues?.headers,
     body: controlValues?.body,
+    rawBody: controlValues?.rawBody,
+    bodyMode: controlValues?.bodyMode,
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-console-preview.tsx`
around lines 509 - 514, controlsKey currently JSON.stringifies only url, method,
headers, and body so changes to controlValues.rawBody or controlValues.bodyMode
won't invalidate cached test results; update the controlsKey construction (the
const controlsKey definition) to include controlValues.rawBody and
controlValues.bodyMode so switching body mode or editing rawBody will produce a
different key and reset test results accordingly.
apps/api/src/app/workflows-v2/usecases/test-http-endpoint/test-http-endpoint.usecase.ts (1)

64-67: Consider handling parseRawBody errors gracefully for better test endpoint UX.

If parseRawBody throws (e.g., invalid JSON or non-object JSON), the error will propagate uncaught, resulting in a 500 error. For a test endpoint, it may be more user-friendly to catch this error and return a descriptive 400 response indicating the raw body is invalid.

✏️ Suggested approach
+    let resolvedBodyPairs: Record<string, unknown>;
+    if (bodyMode === 'raw' && rawJsonBody) {
+      try {
+        resolvedBodyPairs = parseRawBody(rawJsonBody);
+      } catch (error) {
+        const durationMs = Math.round(performance.now() - startTime);
+        return {
+          statusCode: 400,
+          body: { error: error instanceof Error ? error.message : 'Invalid raw body JSON' },
+          headers: {},
+          durationMs,
+          resolvedRequest: { url: resolvedUrl, method, headers: resolvedHeaders },
+        };
+      }
+    } else {
+      resolvedBodyPairs = Object.fromEntries(compiledBody.filter(({ key }) => key).map(({ key, value }) => [key, value]));
+    }
-    const resolvedBodyPairs: Record<string, unknown> =
-      bodyMode === 'raw' && rawJsonBody
-        ? parseRawBody(rawJsonBody)
-        : Object.fromEntries(compiledBody.filter(({ key }) => key).map(({ key, value }) => [key, value]));

Note: startTime would need to be moved before this block.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/api/src/app/workflows-v2/usecases/test-http-endpoint/test-http-endpoint.usecase.ts`
around lines 64 - 67, The code may throw from parseRawBody when bodyMode ===
'raw' and rawJsonBody is invalid, causing an uncaught 500; wrap the parseRawBody
call in a try/catch and, on parse failure or non-object result, return a 400
response with a clear message that the raw body is invalid (including parse
error details), using the same response path your use case returns for bad
requests; ensure startTime (used for timing/logging) is initialized before this
parsing block so timing/logging still works when you early-return.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/curl-display.tsx`:
- Around line 25-43: The current curl-display logic falls back to key/value
`body` when bodyMode === 'raw' but rawBody is empty; update the branch in
curl-display (variables: canHaveBody, bodyMode, rawBody, bodyStr, body) so that
when bodyMode === 'raw' you treat raw mode as exclusive — if rawBody is falsy
set bodyStr to an empty string/null and do not serialize `body`; alternatively
call the existing serializer from curl-utils.ts instead of duplicating logic so
raw-mode behavior matches curl builder and prevents drift.

In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/curl-utils.ts`:
- Around line 35-54: The curl generation currently treats bodyMode === 'raw' as
non-exclusive and falls back to key-value parsing when rawBody is empty; update
the logic in the canHaveBody block so raw mode is handled exclusively: if
bodyMode === 'raw' only use rawBody (set bodyStr when rawBody is present,
otherwise leave bodyStr empty/no fallback), and only run the
key-value/Object.fromEntries branch when bodyMode !== 'raw'; refer to the
variables/functions bodyMode, rawBody, body, bodyStr and the existing key-value
branch to implement this change.
- Around line 36-37: The curl command assembly is vulnerable to unescaped single
quotes in header values and body content (see the header construction and the
branches in curl-utils.ts where bodyMode === 'raw' with rawBody and the
JSON.stringify(bodyObj) branch build --data strings); fix by shell-escaping
single quotes before interpolation (replace each ' with '\'' ) for header values
and for both rawBody and the JSON.stringify(bodyObj) output so the resulting
--header and --data arguments are safe in a single-quoted curl command.

In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-editor.tsx`:
- Around line 36-45: The confirmation text warns the raw body will be discarded
but the handler only changes bodyMode; update handleBodyModeChange so that when
switching from 'raw' to 'key-value' and the user confirms you also clear the raw
body from form state (e.g., call setValue for the raw body field) before calling
saveForm(); alternatively, change the confirmation copy to state that the raw
body will only be ignored while in Key-Value mode rather than discarded—refer to
handleBodyModeChange, bodyMode, rawBody, setValue('bodyMode', ...), saveForm()
to locate where to apply the change.
- Around line 61-87: The two span[role="button"] toggles for bodyMode should be
replaced with the accessible Radix-based primitives: use ToggleGroup
(type="single") with ToggleGroupItem elements instead of the spans; wire
ToggleGroup's value to bodyMode and onValueChange to handleBodyModeChange, and
move the existing className/conditional styling into each ToggleGroupItem so
visual state remains identical while gaining correct ARIA pressed state,
keyboard/focus handling, and semantics; update imports to pull ToggleGroup and
ToggleGroupItem from src/components/primitives and remove the onClick/onKeyDown
handlers from the old spans.

In
`@apps/worker/src/app/workflow/usecases/send-message/execute-http-request-step.usecase.ts`:
- Line 150: The code currently calls parseRawBody inline when computing
bodyObject in executeHttpRequestStep (bodyMode, rawJsonBody, toBodyRecord) which
will throw on malformed JSON and skip creating execution details; wrap the
parseRawBody call in a try/catch, and on catch call CreateExecutionDetails (with
the step id/context and the caught error message) to record the failure before
rethrowing or returning a handled error; ensure bodyObject is assigned a
sensible fallback (e.g., null or an empty record) when parsing fails and that
the catch includes enough context from the request/step to aid observability.

In
`@libs/application-generic/src/dtos/workflow/controls/http-request-control.dto.ts`:
- Around line 51-57: Add a runtime validator restricting allowed values for the
bodyMode property: import and apply the `@IsIn`(['key-value','raw']) decorator to
the bodyMode field (in http-request-control.dto.ts, on the bodyMode property) so
runtime validation matches the TypeScript type; keep `@IsOptional` and `@IsString`
as needed and ensure the `@IsIn` import is added from class-validator.

In `@libs/application-generic/src/usecases/preview/preview.usecase.ts`:
- Around line 215-220: The body selection logic allows a raw mode to fall back
to stale key-value pairs; change the computation of bodyRecord so that when
bodyMode === 'raw' you only use rawJsonBody (parseRawBody(rawJsonBody) if
present, otherwise undefined) and do not fall back to bodyPairs, and when
bodyMode !== 'raw' use bodyPairs via toBodyRecord; update the same pattern in
execute-http-request-step.usecase.ts where similar logic occurs to ensure raw
mode is exclusive.

---

Nitpick comments:
In
`@apps/api/src/app/workflows-v2/usecases/test-http-endpoint/test-http-endpoint.usecase.ts`:
- Around line 64-67: The code may throw from parseRawBody when bodyMode ===
'raw' and rawJsonBody is invalid, causing an uncaught 500; wrap the parseRawBody
call in a try/catch and, on parse failure or non-object result, return a 400
response with a clear message that the raw body is invalid (including parse
error details), using the same response path your use case returns for bad
requests; ensure startTime (used for timing/logging) is initialized before this
parsing block so timing/logging still works when you early-return.

In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-console-preview.tsx`:
- Around line 509-514: controlsKey currently JSON.stringifies only url, method,
headers, and body so changes to controlValues.rawBody or controlValues.bodyMode
won't invalidate cached test results; update the controlsKey construction (the
const controlsKey definition) to include controlValues.rawBody and
controlValues.bodyMode so switching body mode or editing rawBody will produce a
different key and reset test results accordingly.

In `@libs/application-generic/src/services/http-client/http-request.utils.ts`:
- Around line 21-28: In parseRawBody, add a blank line immediately before the
final return statement in the function parseRawBody to follow the coding
guideline requiring a blank line before every return; keep the function logic
unchanged and only insert the empty line above the return parsed as
Record<string, unknown>.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fb1ed1f7-727b-4942-ba97-42853c2ac77b

📥 Commits

Reviewing files that changed from the base of the PR and between 6788d83 and 15f7166.

📒 Files selected for processing (15)
  • apps/api/src/app/workflows-v2/usecases/test-http-endpoint/test-http-endpoint.usecase.ts
  • apps/dashboard/src/components/workflow-editor/steps/component-utils.tsx
  • apps/dashboard/src/components/workflow-editor/steps/http-request/configure-http-request-step-preview.tsx
  • apps/dashboard/src/components/workflow-editor/steps/http-request/curl-display.tsx
  • apps/dashboard/src/components/workflow-editor/steps/http-request/curl-utils.ts
  • apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-console-preview.tsx
  • apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-editor.tsx
  • apps/dashboard/src/components/workflow-editor/steps/http-request/raw-body-editor.tsx
  • apps/worker/src/app/workflow/usecases/send-message/execute-http-request-step.usecase.ts
  • libs/application-generic/src/dtos/workflow/controls/http-request-control.dto.ts
  • libs/application-generic/src/services/http-client/http-request.utils.spec.ts
  • libs/application-generic/src/services/http-client/http-request.utils.ts
  • libs/application-generic/src/usecases/preview/preview.usecase.ts
  • packages/shared/src/consts/providers/channels/http-request.ts
  • packages/shared/src/dto/workflows/step.dto.ts

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 15f7166. Configure here.

FredRMonizze and others added 2 commits April 10, 2026 14:21
- Use ToggleGroup primitive for body mode toggle (proper ARIA, keyboard
  handling) instead of custom span buttons
- Wrap parseRawBody in try/catch in execute-http-request-step usecase and
  create execution details on parse failure (was throwing silently)
- Wrap parseRawBody in try/catch in test-http-endpoint usecase and return
  400 with clear message instead of uncaught 500
- Add @isin validator on bodyMode field in HttpRequestControlDto
- Make raw mode exclusive in preview and execute usecases (no fallback
  to stale key-value pairs when bodyMode is raw)
- Include rawBody and bodyMode in controlsKey to invalidate test cache
  when switching modes or editing raw body
- Use local draft state in RawBodyEditor so the form (and preview) only
  updates when JSON is valid, while the user can still freely type

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the user confirms switching from raw to key-value mode, also clear
the rawBody field so the discard message matches actual behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/raw-body-editor.tsx`:
- Around line 20-23: The JSON validator in raw-body-editor.tsx (validateJson)
currently rejects top-level arrays by checking Array.isArray(parsed) and
returning 'Body must be a JSON object'; change the validation to accept both
objects and arrays: after JSON.parse(value) ensure parsed is not null and that
it's either an object or an array (i.e., remove the Array.isArray(parsed)
rejection and update the error message to reflect "Body must be valid JSON" or
"Body must be a JSON object or array"); update any related conditional that uses
parsed to distinguish behavior when an object vs array is required downstream if
necessary.
- Around line 62-69: The onChange handler currently persists whitespace-only
drafts verbatim; update the save path so after computing newVal (and calling
setDraft) you normalize whitespace-only content to an empty string before
propagating: use validateJson(newVal) as before, but when deciding what to
persist call something like trimmed = newVal.trim() and if trimmed === '' pass
'' to field.onChange and saveForm, otherwise pass the original newVal; touch the
onChange block around setDraft, validateJson, field.onChange, and saveForm to
implement this.

In
`@apps/worker/src/app/workflow/usecases/send-message/execute-http-request-step.usecase.ts`:
- Around line 151-157: The raw-body handling currently narrows payloads to
Record<string, unknown> which rejects top-level JSON arrays; update the parsing
and type usage so raw JSON can be any JSON value (object or array). Change the
local variable in execute-http-request-step.usecase.ts from Record<string,
unknown> | undefined to unknown | undefined (or a JSONValue type that includes
arrays), update parseRawBody in http-request.utils.ts to return unknown (or
JSONValue) instead of Record<string, unknown>, and adjust shouldIncludeBody and
the preview/test codepaths in preview.usecase.ts (the HMAC generation path) to
accept the widened type so top-level arrays like [{"id":1}] are allowed
end-to-end.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 663c4792-d6cf-40c2-af40-4b9a0d24c586

📥 Commits

Reviewing files that changed from the base of the PR and between 15f7166 and 4b6e451.

📒 Files selected for processing (7)
  • apps/api/src/app/workflows-v2/usecases/test-http-endpoint/test-http-endpoint.usecase.ts
  • apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-console-preview.tsx
  • apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-editor.tsx
  • apps/dashboard/src/components/workflow-editor/steps/http-request/raw-body-editor.tsx
  • apps/worker/src/app/workflow/usecases/send-message/execute-http-request-step.usecase.ts
  • libs/application-generic/src/dtos/workflow/controls/http-request-control.dto.ts
  • libs/application-generic/src/usecases/preview/preview.usecase.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-console-preview.tsx
  • apps/api/src/app/workflows-v2/usecases/test-http-endpoint/test-http-endpoint.usecase.ts
  • libs/application-generic/src/dtos/workflow/controls/http-request-control.dto.ts
  • apps/dashboard/src/components/workflow-editor/steps/http-request/http-request-editor.tsx

…drafts

- Allow top-level JSON arrays in raw body mode (parseRawBody, validateJson,
  shouldIncludeBody) — APIs like batch endpoints expect arrays at the root
- Update parseRawBody return type to Record<string, unknown> | unknown[]
- Update bodyObject types in execute, preview, and test usecases accordingly
- Persist whitespace-only raw body drafts as empty string so the backend
  doesn't see a non-empty body containing only spaces
- Update unit tests to verify array support
Both CurlDisplay and buildRawCurlString still fell back to rendering the
key-value body when bodyMode === 'raw' but rawBody was empty. This made
the preview show a payload that the backend would not actually send.

Now in raw mode, the curl preview only renders rawBody (or nothing).
Headers, URL, and body values containing a single quote (e.g.
{"text":"it's ok"}) would break the generated curl command because
single quotes cannot appear inside POSIX shell single-quoted strings.

Add an escapeShellSingleQuoted helper that closes, escapes, and reopens
the quote ('\''), and apply it everywhere curl-utils and curl-display
interpolate user-provided values into the rendered curl command.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/dashboard/src/components/workflow-editor/steps/http-request/curl-utils.ts (1)

13-15: Match the repo's return-spacing rule in this helper.

Please add a blank line before the return here to keep the file aligned with the shared TypeScript formatting convention.

As per coding guidelines, "Include a blank line before every return statement".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/curl-utils.ts`
around lines 13 - 15, The helper function escapeShellSingleQuoted currently
returns immediately without a preceding blank line; update the function
(escapeShellSingleQuoted) to insert a blank line before the return statement to
comply with the repo's "blank line before return" formatting rule and ensure the
file matches shared TypeScript conventions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/curl-utils.ts`:
- Around line 67-71: The generated curl command omits the provided method
parameter, so the parts array (`parts`) must include a `--request` option to
reflect non-GET methods; update the first element (the string built with
`escapeShellSingleQuoted(url || 'https://api.example.com/endpoint')`) to include
`--request '${method}'` (use the `method` variable, preferably uppercased) so
the resulting command shows the correct HTTP verb alongside `headerArgs` and
`bodyStr`.

---

Nitpick comments:
In
`@apps/dashboard/src/components/workflow-editor/steps/http-request/curl-utils.ts`:
- Around line 13-15: The helper function escapeShellSingleQuoted currently
returns immediately without a preceding blank line; update the function
(escapeShellSingleQuoted) to insert a blank line before the return statement to
comply with the repo's "blank line before return" formatting rule and ensure the
file matches shared TypeScript conventions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 04bf6697-9f19-4aa9-94e6-50750010968d

📥 Commits

Reviewing files that changed from the base of the PR and between d3373c6 and 5881580.

📒 Files selected for processing (2)
  • apps/dashboard/src/components/workflow-editor/steps/http-request/curl-display.tsx
  • apps/dashboard/src/components/workflow-editor/steps/http-request/curl-utils.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/src/components/workflow-editor/steps/http-request/curl-display.tsx

The generated curl command always omitted the --request flag, so non-GET
methods (POST, PUT, etc.) rendered as plain GET requests in the preview,
which was misleading.

Add --request '<METHOD>' to both buildRawCurlString and CurlDisplay,
escaping the method for shell safety.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant