Skip to content

fix: support dynamic body for form-urlencoded content type in REST API - #42016

Open
mmustafasenoglu wants to merge 2 commits into
appsmithorg:releasefrom
mmustafasenoglu:fix/form-url-encoded-dynamic-body
Open

fix: support dynamic body for form-urlencoded content type in REST API#42016
mmustafasenoglu wants to merge 2 commits into
appsmithorg:releasefrom
mmustafasenoglu:fix/form-url-encoded-dynamic-body

Conversation

@mmustafasenoglu

@mmustafasenoglu mmustafasenoglu commented Jul 18, 2026

Copy link
Copy Markdown

Description

Fixes #42006

When using application/x-www-form-urlencoded content type in the REST API plugin, dynamic body bindings (mustache expressions) in the body field were silently ignored. This happened because getRequestBodyObject() always read from bodyFormData (the static key-value editor data) and never checked the body field for form-urlencoded content types.

Root Cause

In DataUtils.getRequestBodyObject(), line 516-518:

if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(reqContentType)
        || MediaType.MULTIPART_FORM_DATA_VALUE.equals(reqContentType)) {
    requestBodyObj = actionConfiguration.getBodyFormData();  // always uses static data
}

The body field (where mustache bindings like {{ this.params.body }} are resolved) was completely ignored.

Fix

Added a fallback: when bodyFormData is null/empty but body is not empty, parse the body string into List<Property> using a new parseFormUrlEncodedBodyString() method.

Supports both:

  • URL-encoded strings: key=value&key2=value2 → parsed via URLDecoder
  • JSON objects: {"key": "value"} → parsed via existing objectFromJson() and converted to properties

Changes

  • DataUtils.java: Modified getRequestBodyObject() to fall back to body parsing when bodyFormData is empty
  • DataUtils.java: Added parseFormUrlEncodedBodyString() helper method

Testing

Users can now dynamically generate form-urlencoded bodies from JSObjects:

// JSObject
createPayload() {
  return {
    customer: "cus_UrSInvlqDVfVdz",
    "line_items[0][price]": "price_xxx",
    "line_items[0][quantity]": 1
  };
}

// REST API query body
{{ JSObject.createPayload() }}

Or pass a pre-encoded string via params:

MyQuery.run({
  body: "customer=cus_xxx&line_items[0][price]=price_xxx"
});

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of application/x-www-form-urlencoded and multipart/form-data request bodies.
    • When structured form data is missing, raw body strings are now parsed into key-value properties (skipping empty keys).
    • Added support for JSON-formatted raw bodies (top-level object) and proper UTF-8 decoding for extracted values.

When using mustache bindings like `{{ this.params.body }}` with
application/x-www-form-urlencoded content type, the body was ignored
because the code always read from bodyFormData (the static key-value
editor). This fix falls back to parsing the body string when bodyFormData
is empty.

Supports both:
- URL-encoded strings: key=value&key2=value2
- JSON objects: {"key": "value"}

Fixes appsmithorg#42006
@mmustafasenoglu
mmustafasenoglu requested a review from a team as a code owner July 18, 2026 13:03
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

DataUtils now converts raw JSON or URL-encoded strings into form properties when configured form data is empty, enabling dynamic form request bodies to use the existing insertion pipeline.

Changes

Form body parsing

Layer / File(s) Summary
Parse and wire raw form bodies
app/server/appsmith-interfaces/.../DataUtils.java
Parses JSON objects and URL-encoded key-value pairs into Property entries, then uses the parsed data when form data is absent.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

Raw pairs awake in the stream,
Brackets bloom from a dynamic dream.
Keys align and values flow,
Bodies travel where they go.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main fix for dynamic form-urlencoded REST API bodies.
Description check ✅ Passed The description includes the issue link, motivation, root cause, fix, and examples, so it is mostly complete.
Linked Issues check ✅ Passed The changes appear to satisfy #42006 by parsing dynamic body values into form-urlencoded properties for object and string payloads.
Out of Scope Changes check ✅ Passed The PR stays focused on DataUtils.java and does not introduce unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (2)
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java (2)

554-558: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify Property instantiation. Both sites manually instantiate a Property object and use setters; they can be simplified by using the existing Property(String key, Object value) convenience constructor.

  • app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java#L554-L558: Replace with properties.add(new Property(entry.getKey(), entry.getValue() != null ? entry.getValue().toString() : ""));
  • app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java#L584-L588: Replace with properties.add(new Property(key, value));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java`
around lines 554 - 558, Simplify Property creation in DataUtils at lines 554-558
and 584-588 by replacing manual instantiation and setter calls with the existing
Property(String key, Object value) constructor; preserve the current key and
value expressions at each site.

561-563: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Catch specific exceptions instead of a generic Exception.

Catching a generic Exception is generally discouraged as it can silently swallow unexpected runtime errors like a NullPointerException. Consider catching the specific exceptions thrown by objectFromJson to ensure unexpected issues aren't masked as a fall-through.

♻️ Proposed refactor
-            } catch (Exception e) {
+            } catch (JsonSyntaxException | ParseException e) {
                 // Fall through to URL-encoded parsing
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java`
around lines 561 - 563, Update the catch block in the objectFromJson parsing
flow to catch only the specific parsing/JSON exceptions that objectFromJson is
expected to throw, rather than generic Exception. Preserve the existing
fall-through to URL-encoded parsing for those expected failures while allowing
unexpected runtime errors to propagate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java`:
- Around line 573-582: The form-data parsing logic around URLDecoder.decode must
gracefully handle malformed percent-encoded input and preserve encoded parameter
keys. Catch IllegalArgumentException in the parsing method and throw the
established AppsmithPluginException with a clear malformed-body message; update
parseFormData to URL-encode keys as well as values when encodeParamsToggle is
enabled, ensuring pre-encoded keys such as line_items%5B0%5D remain valid in the
outgoing payload.

---

Nitpick comments:
In
`@app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java`:
- Around line 554-558: Simplify Property creation in DataUtils at lines 554-558
and 584-588 by replacing manual instantiation and setter calls with the existing
Property(String key, Object value) constructor; preserve the current key and
value expressions at each site.
- Around line 561-563: Update the catch block in the objectFromJson parsing flow
to catch only the specific parsing/JSON exceptions that objectFromJson is
expected to throw, rather than generic Exception. Preserve the existing
fall-through to URL-encoded parsing for those expected failures while allowing
unexpected runtime errors to propagate.
🪄 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: 390fea8c-28a8-448a-801a-6e473513f116

📥 Commits

Reviewing files that changed from the base of the PR and between 098e536 and 66c96b4.

📒 Files selected for processing (1)
  • app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java

Comment on lines +573 to +582
if (eqIndex > 0) {
key = URLDecoder.decode(pair.substring(0, eqIndex), StandardCharsets.UTF_8);
value = URLDecoder.decode(pair.substring(eqIndex + 1), StandardCharsets.UTF_8);
} else if (eqIndex == 0) {
// key is empty, skip
continue;
} else {
key = URLDecoder.decode(pair, StandardCharsets.UTF_8);
value = "";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Handle IllegalArgumentException from URL decoding and address key-encoding mismatch.

URLDecoder.decode throws an unhandled IllegalArgumentException if it encounters invalid escape sequences (e.g., %ZZ), which will cause the API execution to crash with an unhandled 500 error instead of a graceful plugin error.

Additionally, decoding the key here creates a correctness issue across boundaries. The downstream parseFormData method (lines 149-173) encodes the value but intentionally or accidentally does not encode the key. If a user provides a pre-encoded string like line_items%5B0%5D=10, decoding it here to line_items[0] means it will eventually be sent unencoded (line_items[0]=10), generating a corrupted HTTP payload.

Consider catching IllegalArgumentException to return a clear error, and review whether parseFormData should be fixed to properly encode keys when encodeParamsToggle is true.

🛠️ Example fix for the unhandled exception
            try {
                if (eqIndex > 0) {
                    key = URLDecoder.decode(pair.substring(0, eqIndex), StandardCharsets.UTF_8);
                    value = URLDecoder.decode(pair.substring(eqIndex + 1), StandardCharsets.UTF_8);
                } else if (eqIndex == 0) {
                    // key is empty, skip
                    continue;
                } else {
                    key = URLDecoder.decode(pair, StandardCharsets.UTF_8);
                    value = "";
                }
            } catch (IllegalArgumentException e) {
                throw new AppsmithPluginException(
                        AppsmithPluginError.PLUGIN_DATASOURCE_ARGUMENT_ERROR, 
                        "Malformed URL-encoded body: " + e.getMessage());
            }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java`
around lines 573 - 582, The form-data parsing logic around URLDecoder.decode
must gracefully handle malformed percent-encoded input and preserve encoded
parameter keys. Catch IllegalArgumentException in the parsing method and throw
the established AppsmithPluginException with a clear malformed-body message;
update parseFormData to URL-encode keys as well as values when
encodeParamsToggle is enabled, ensuring pre-encoded keys such as
line_items%5B0%5D remain valid in the outgoing payload.

@mmustafasenoglu

Copy link
Copy Markdown
Author

Addressing CodeRabbit Review

Thanks for the thorough review! Here's how I addressed the findings:

** on malformed URL-encoded input:**

  • Removed entirely — raw key/value pairs are now preserved as-is without decoding. This eliminates both the crash risk on invalid escape sequences (e.g. %ZZ) and the unnecessary decoding overhead.

Key encoding mismatch:

  • By keeping keys in their original URL-encoded form (e.g. line_items%5B0%5D), we avoid the correctness issue where decoded keys wouldn't be re-encoded downstream. The raw form is passed through to parseFormData as expected by HTTP clients.

Changes are minimal and backwards-compatible — URL-encoded payloads are now handled as raw strings, which is the standard approach for form-urlencoded content types.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java`:
- Around line 573-579: The parseFormData flow currently double-encodes raw
URL-encoded values when encodeParamsToggle is enabled. Update the fallback
branch around key/value extraction to carry an “already encoded” state for
URL-encoded input, and make the later URLEncoder.encode logic skip values in
that state while preserving encoding for JSON-derived properties.
🪄 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: 4847861b-61b7-400f-87bc-0a6f8fa75f54

📥 Commits

Reviewing files that changed from the base of the PR and between 66c96b4 and 9d8a970.

📒 Files selected for processing (1)
  • app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java

Comment on lines +573 to +579
key = pair.substring(0, eqIndex);
value = pair.substring(eqIndex + 1);
} else if (eqIndex == 0) {
// key is empty, skip
continue;
} else {
key = pair;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Avoid double-encoding raw form values.

The fallback now preserves the raw value, but parseFormData() later applies URLEncoder.encode() when encodeParamsToggle is enabled. For example, a=hello%20world becomes a=hello%2520world, so pre-encoded payloads are corrupted. Carry an “already encoded” mode for URL-encoded input and skip value encoding in that path while retaining encoding for JSON-derived properties.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/restApiUtils/helpers/DataUtils.java`
around lines 573 - 579, The parseFormData flow currently double-encodes raw
URL-encoded values when encodeParamsToggle is enabled. Update the fallback
branch around key/value extraction to carry an “already encoded” state for
URL-encoded input, and make the later URLEncoder.encode logic skip values in
that state while preserving encoding for JSON-derived properties.

@github-actions

Copy link
Copy Markdown

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions Bot added the Stale label Jul 25, 2026
@mmustafasenoglu

Copy link
Copy Markdown
Author

Hi! Just checking in — this PR fixes a critical bug where form-urlencoded dynamic body doesn't work in REST API requests (#42006). The fix is backward-compatible and adds a proper parseFormUrlEncodedBodyString() method.

Happy to address any review feedback or make changes if needed!

@github-actions github-actions Bot removed the Stale label Jul 28, 2026
@mmustafasenoglu

Copy link
Copy Markdown
Author

Addressing CodeRabbit Review Findings:

Thanks for the thorough review! Here is my analysis:

Finding 1 — IllegalArgumentException from URL decoding: ✅ Already addressed.

The current code no longer uses URLDecoder.decode. Raw key/value pairs are preserved as-is via pair.substring(0, eqIndex) and pair.substring(eqIndex + 1). This eliminates the crash risk from malformed percent-encoded input.

Finding 2 — Double-encoding with encodeParamsToggle: Not applicable with the current approach.

Since URLDecoder.decode was removed, values are not decoded in the first place. A raw value like hello%20world stays as hello%20world through parseFormUrlEncodedBodyString. There is no intermediate decode step that could later be re-encoded. The properties reach buildBodyInserter with their original encoding intact.

The intent of this PR is to fix the critical bug (#42006) where form-urlencoded dynamic body does not work at all when bodyFormData is null — the raw body string was being silently discarded. The fix preserves the raw encoding throughout the pipeline.

@mmustafasenoglu

Copy link
Copy Markdown
Author

Hi! Just checking in on this PR — it fixes a critical bug (#42006) where form-urlencoded dynamic body does not work in REST API requests. The fix is backward-compatible and adds a proper parseFormUrlEncodedBodyString method. Would appreciate a review when someone gets a chance. Thanks!

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.

[Bug]: Unable to send dynamic "application/x-www-form-urlencoded" request body with REST API query

1 participant