<p>There's a couple of issues here – right now, the request can't work for multiple reasons.</p>
<h2>FormData and JSON</h2>
<p>You can't stringify a <code>FormData</code> object directly, this will only ever give you an empty object <code>{}</code> as a result. You can work around that by manually iterating through the entries and creating an object to stringify (see <a href="https://stackoverflow.com/questions/41431322/how-to-convert-formdata-html5-object-to-json">this SO question</a> for details). But at it's core, the <code>FormData</code> class isn't really intended for this. It's normally used to mimic 'traditional' form submissions using <code>application/x-www-form-urlencoded</code> or <code>multipart/form-data</code> encodings. If you want to use those, just supply the <code>FormData</code> object to fetch and include the corresponding Content-Type. If you really need JSON, I wouldn't use <code>FormData</code> at all.</p>
<h2>Routing</h2>
<p>Since the <code>body</code> is empty, the request probably isn't routed to your controller at all (unless <code>mySiteUrl</code> points to your Controller's action URL as well). Also, I don't think Yii's routing system handles <code>action</code> parameters that are included as part of an encoded JSON payload. So you'll need to provide the <code>action</code> parameter in the URL as a query parameter, send the request to the action URL directly or include the action as a header.</p>
<h2>Mismatch between body and content-type</h2>
<p>You're passing a JSON-encoded string but not not specifying a <code>Content-Type</code> header with <code>application/json</code>. This is probably why Guzzle is complaining. You're gonna have to decide between using a JSON payload or using one of the traditional form methods (see above), then send the appropriate <code>Content-Type</code> header:</p>
<ul>
<li>If you want to send encoded JSON, specify <code>Content-Type: application/json</code>. - If you want to access the body parameters through <code>$_POST</code> (or <code>Craft::$app-&gt;request-&gt;post('someParameter')</code>), you'll need to set the <code>Content-Type</code> header to <code>application/x-www-form-urlencoded</code> or <code>multipart/form-data</code>. In this case, don't stringify the <code>FormData</code> object, but pass it as the body parameter to fetch as-is.</li>
</ul>
<hr />
<p>For all of those issues, you'll have an easier time to discover and fix them by using your Browser's Devtools. For example, you can quickly verify the behaviour of <code>JSON.stringify(FormData)</code> in the Console. To check if the request actually contains the payload you want it to, and to see the response, use the Network tab. This will help you spot any problems with your code much faster.</p>

CC BY-SA 4.0
2022-03-07T10:23:47.493Z
2022-03-07T10:23:47.493Z
MoritzLost
<p>When i send body: JSON.stringify(formData) to my plugin controller the payload is empty.</p>
<p>When i send just as body: formData then the payload is there but</p>
<pre><code>json_decode(Craft::$app-&gt;getRequest()-&gt;rawBody) is empty.

</code></pre>
<p>I can access post data like:</p>
<pre><code>Craft::$app-&gt;getRequest()-&gt;post('FIRSTNAME');
</code></pre>
<p>But then i run into issues with using guzzle complaining a mismatch type.
Been stumped for days as to why I can submit other forms via ajax/fetch to plugins but this form will not play nicely</p>
<pre><code>var formData = new FormData(form_element);
    formData.append('action', 'dot-mailer-subscribe/default/subscribe');

    const CSRF = document.getElementById('subscribe-modal-token').value
    fetch(mySiteUrl, {
        method: 'POST',
        // body: formData,
        body: JSON.stringify(formData),
        headers: {
            &quot;Accept&quot;: &quot;application/json&quot;,
            &quot;CRAFT_CSRF_TOKEN&quot;: CSRF
        },
    })
</code></pre>

<plugins><form><ajax>
fetch post request to plugin shows payload empty when sent as json stringify
# fetch post request to plugin shows payload empty when sent as json stringify

(Asked by: username_0 on 2022-03-07)

When i send body: JSON.stringify(formData) to my plugin controller the payload is empty.
When i send just as body: formData then the payload is there but
json_decode(Craft::$app->getRequest()->rawBody) is empty.


I can access post data like:
Craft::$app->getRequest()->post('FIRSTNAME');

But then i run into issues with using guzzle complaining a mismatch type.
Been stumped for days as to why I can submit other forms via ajax/fetch to plugins but this form will not play nicely
var formData = new FormData(form_element);
    formData.append('action', 'dot-mailer-subscribe/default/subscribe');

    const CSRF = document.getElementById('subscribe-modal-token').value
    fetch(mySiteUrl, {
        method: 'POST',
        // body: formData,
        body: JSON.stringify(formData),
        headers: {
            "Accept": "application/json",
            "CRAFT_CSRF_TOKEN": CSRF
        },
    })

**Tags:** plugins, form, ajax

---

## 1 answers

### Answer by username_1 on 2022-03-07. Score: 1

There's a couple of issues here – right now, the request can't work for multiple reasons.

## FormData and JSON

You can't stringify a `FormData` object directly, this will only ever give you an empty object `{}` as a result. You can work around that by manually iterating through the entries and creating an object to stringify (see [this SO question](https://stackoverflow.com/questions/41431322/how-to-convert-formdata-html5-object-to-json) for details). But at it's core, the `FormData` class isn't really intended for this. It's normally used to mimic 'traditional' form submissions using `application/x-www-form-urlencoded` or `multipart/form-data` encodings. If you want to use those, just supply the `FormData` object to fetch and include the corresponding Content-Type. If you really need JSON, I wouldn't use `FormData` at all.

## Routing

Since the `body` is empty, the request probably isn't routed to your controller at all (unless `mySiteUrl` points to your Controller's action URL as well). Also, I don't think Yii's routing system handles `action` parameters that are included as part of an encoded JSON payload. So you'll need to provide the `action` parameter in the URL as a query parameter, send the request to the action URL directly or include the action as a header.

## Mismatch between body and content-type

You're passing a JSON-encoded string but not not specifying a `Content-Type` header with `application/json`. This is probably why Guzzle is complaining. You're gonna have to decide between using a JSON payload or using one of the traditional form methods (see above), then send the appropriate `Content-Type` header:

* If you want to send encoded JSON, specify `Content-Type: application/json`. - If you want to access the body parameters through `$_POST` (or `Craft::$app->request->post('someParameter')`), you'll need to set the `Content-Type` header to `application/x-www-form-urlencoded` or `multipart/form-data`. In this case, don't stringify the `FormData` object, but pass it as the body parameter to fetch as-is.

---

For all of those issues, you'll have an easier time to discover and fix them by using your Browser's Devtools. For example, you can quickly verify the behaviour of `JSON.stringify(FormData)` in the Console. To check if the request actually contains the payload you want it to, and to see the response, use the Network tab. This will help you spot any problems with your code much faster.


---

