Html: W3C HTML JSON form submission

Created on 13 Aug 2016  路  11Comments  路  Source: whatwg/html

Hello WHATWG! I'm reading the section for enctype and found that there's no state for application/json or something similar that allows form submission in JSON.

I ignore the reasons that forced W3C to stop maintaining that specification. But I'm wondering if that spec worths or not?

Thanks for your time.

Most helpful comment

Coming a bit late (6 month) to this topic (just saw it), but would like to share my view on application/json as "enctype" attribute value

JSON, form URL encoded, and plain text

JSON encoding is more or less like the "x-www-form-urlencoded" format. It is not designed to embed binary data. As such, both the application/x-www-form-urlencoded serializer and the text/plain encoding algorythm says that they serialize "file" entries in form data by replacing their value with their file's name only. Base64 encoding has been estimated as a no go for files use case (to much overhead).

So I think it would be fair to says that either native XHR/fetch support or form data toJSON() method should behave the same.

What for?

Well

  • URL encoding/decoding entry values can get a real cost for non ascii characters (UTF-8 is usually encoded in percent values), while JSON support utf-8 from start.
  • values types could be better represented (see the next "What for?" section at the end of this comment)

Multipart, form-data, and JSON

The way we send files over XMLHttpRequest / Fetch is either sending directly a File/Blob/ArrayBuffer as the main body or via a FormData, with files entries, using the "multipart/form-data" encoding.
"multipart" is the MIME type standard to mix binary, plain text, and any formatted data in "parts" joined in a single body.

So if we would like to send Form entries including files using JSON encoding, the only approach I would imagine is defining a "multipart/json-form-data" or more easily "multipart/form-data+json" (standard way to indicate a JSON flavor of an existing format. It would look very much like classic "form-data" but may benefit from few JSON formating advantages.

In multipart/form-data MIME format, each Form entry becomes a MIME part with its own Headers.

The main "part header" is Content-Disposition. (ex: Content-Disposition: form-data; name="field1"). It provides the form entry name. If the entry is a file, it cans contain also the file name (ex: Content-Disposition: form-data; name="myFile"; filename="summary.pdf")

The second main "part header" is Content-Type, which default value is "text/plain" if not provided (as for standard input entries), but this value is important for files. It can have a specific MIME type, if detected, based on the embedded file (ex: application/pdf). By default it will be "application/octet-stream".

In a JSON flavor, "non-file" parts could have their "Content-type" set to "application/json"

What for?

  • HTML5 form entries having a specific type like "number" could be differentiated from the text related ones like "text" (default), "search", or "url"
  • "checkbox" values could be represented as real boolean values (if no text value is specified, Chrome returns me the text "on", if it is checked, in classic the form-data format)
  • entries with multiple values (<select>, "radio" type, or other <input> entries with the multiple attribute) could be grouped in a single part using the array JSON notation (for non-binary ones)

That's all... Just wanted to share what kind of bell this feature request did ring to me.

Still, I agree, server side frameworks usually work pretty well with classic form data... But well, getting automatically the right value type would be an extra I often felt was missing.

PS: of course another thing is to consider if such "enctype" is acceptable with both GET/POST methods, or only for POST ones (like multipart/form-data), potentially because some HTTP client/proxy/server may not support JSON in URLs if not URL encoded...

All 11 comments

It's a lot of added complexity for little value. And there is no implementer interest because of that.

If I want to convert a form into an object, I may implement a simple solution... something like

      // convert the form into an object
      var formObj = {};
      for (var i = 0; i < form.length; i++) {
        if (form[i].id) {
          formObj[form[i].id] = form[i].value;
        }
      }

@annevk, thanks for the information.

You can also use FormData(form). Perhaps we should expose a toJSON on FormData. That might be fairly reasonable.

Hmm... sounds good.
Here's my current version, without toJSON()

    form.addEventListener('submit', e => {
      e.preventDefault();

      var formObj = {};
      var fd = new FormData(e.target);
      for (var item of fd) {
        formObj[item[0]] = item[1];
      }

      fetch(`/api/category/${formObj.id}`, {
        method: 'put',
        headers: new Headers({
          'Content-Type': 'application/json'
        }),
        body: JSON.stringify(formObj)
      });
    });

Let me dream a bit, please...
With toJSON()

    form.addEventListener('submit', e => {
      e.preventDefault();

      var fd = new FormData(e.target).toJSON();
      fetch(`/api/category/${formObj.id}`, {
        method: 'put',
        body: fd  // then the fetch process should guess the content-type
      });
    });

Or just by setting the content-type

    form.addEventListener('submit', e => {
      e.preventDefault();

      var fd = new FormData(e.target);
      fetch(`/api/category/${formObj.id}`, {
        method: 'put',
        headers: new Headers({
          'Content-Type': 'application/json'
        }),
        body: fd // the fetch process will call toJSON automatically
      });
    });

The main goal that I see here is the possibility to expose the form depending on the content-type.

@annevk do you want to move this to XHR to add a toJSON() and close this issue?

I opened https://github.com/whatwg/xhr/issues/84 though given your comments in https://github.com/whatwg/url/issues/143 I wonder whether returning a JSON object here is the way to go.

@rianby64 if you're satisfied with this resolution please close this issue. Your last idea goes a tad too far I think. We don't really want browsers to inspect the headers to determine how to serialize a value. That's too much action-at-a-distance.

So, the first variant seems to be better than the second one. Nice :smile: ! Thanks a million!

Coming a bit late (6 month) to this topic (just saw it), but would like to share my view on application/json as "enctype" attribute value

JSON, form URL encoded, and plain text

JSON encoding is more or less like the "x-www-form-urlencoded" format. It is not designed to embed binary data. As such, both the application/x-www-form-urlencoded serializer and the text/plain encoding algorythm says that they serialize "file" entries in form data by replacing their value with their file's name only. Base64 encoding has been estimated as a no go for files use case (to much overhead).

So I think it would be fair to says that either native XHR/fetch support or form data toJSON() method should behave the same.

What for?

Well

  • URL encoding/decoding entry values can get a real cost for non ascii characters (UTF-8 is usually encoded in percent values), while JSON support utf-8 from start.
  • values types could be better represented (see the next "What for?" section at the end of this comment)

Multipart, form-data, and JSON

The way we send files over XMLHttpRequest / Fetch is either sending directly a File/Blob/ArrayBuffer as the main body or via a FormData, with files entries, using the "multipart/form-data" encoding.
"multipart" is the MIME type standard to mix binary, plain text, and any formatted data in "parts" joined in a single body.

So if we would like to send Form entries including files using JSON encoding, the only approach I would imagine is defining a "multipart/json-form-data" or more easily "multipart/form-data+json" (standard way to indicate a JSON flavor of an existing format. It would look very much like classic "form-data" but may benefit from few JSON formating advantages.

In multipart/form-data MIME format, each Form entry becomes a MIME part with its own Headers.

The main "part header" is Content-Disposition. (ex: Content-Disposition: form-data; name="field1"). It provides the form entry name. If the entry is a file, it cans contain also the file name (ex: Content-Disposition: form-data; name="myFile"; filename="summary.pdf")

The second main "part header" is Content-Type, which default value is "text/plain" if not provided (as for standard input entries), but this value is important for files. It can have a specific MIME type, if detected, based on the embedded file (ex: application/pdf). By default it will be "application/octet-stream".

In a JSON flavor, "non-file" parts could have their "Content-type" set to "application/json"

What for?

  • HTML5 form entries having a specific type like "number" could be differentiated from the text related ones like "text" (default), "search", or "url"
  • "checkbox" values could be represented as real boolean values (if no text value is specified, Chrome returns me the text "on", if it is checked, in classic the form-data format)
  • entries with multiple values (<select>, "radio" type, or other <input> entries with the multiple attribute) could be grouped in a single part using the array JSON notation (for non-binary ones)

That's all... Just wanted to share what kind of bell this feature request did ring to me.

Still, I agree, server side frameworks usually work pretty well with classic form data... But well, getting automatically the right value type would be an extra I often felt was missing.

PS: of course another thing is to consider if such "enctype" is acceptable with both GET/POST methods, or only for POST ones (like multipart/form-data), potentially because some HTTP client/proxy/server may not support JSON in URLs if not URL encoded...

I also think it would be useful to make enctype="application/json" work

<form method="post" action="https://httpbin/post" enctype="application/json">
  <input name="foo" value="bar">
  <input type="submit">
</form>

https://jsfiddle.net/crl/cj9f0qna/ foo=bar is sent when submitting, instead of {"foo":"bar"} if enctype="application/json" were implemented

The problem is that any on-the-wire extension to forms requires navigation to become CORS-aware, which would be rather involved and with lots of details to think through. Coupled with lack of active implementer interest it doesn't really seem like something that's going to happen anytime soon.

Perhaps once navigation is refactored better so that it's more clear what the consequences would be.

Was this page helpful?
0 / 5 - 0 ratings