How do I POST with multipart form data using fetch?

198,822

Solution 1

You're setting the Content-Type to be multipart/form-data, but then using JSON.stringify on the body data, which returns application/json. You have a content type mismatch.

You will need to encode your data as multipart/form-data instead of json. Usually multipart/form-data is used when uploading files, and is a bit more complicated than application/x-www-form-urlencoded (which is the default for HTML forms).

The specification for multipart/form-data can be found in RFC 1867.

For a guide on how to submit that kind of data via javascript, see here.

The basic idea is to use the FormData object (not supported in IE < 10):

async function sendData(url, data) {
  const formData  = new FormData();

  for(const name in data) {
    formData.append(name, data[name]);
  }

  const response = await fetch(url, {
    method: 'POST',
    body: formData
  });

  // ...
}

Per this article make sure not to set the Content-Type header. The browser will set it for you, including the boundary parameter.

Solution 2

I was recently working with IPFS and worked this out. A curl example for IPFS to upload a file looks like this:

curl -i -H "Content-Type: multipart/form-data; boundary=CUSTOM" -d $'--CUSTOM\r\nContent-Type: multipart/octet-stream\r\nContent-Disposition: file; filename="test"\r\n\r\nHello World!\n--CUSTOM--' "http://localhost:5001/api/v0/add"

The basic idea is that each part (split by string in boundary with --) has it's own headers (Content-Type in the second part, for example.) The FormData object manages all this for you, so it's a better way to accomplish our goals.

This translates to fetch API like this:

const formData = new FormData()
formData.append('blob', new Blob(['Hello World!\n']), 'test')

fetch('http://localhost:5001/api/v0/add', {
  method: 'POST',
  body: formData
})
.then(r => r.json())
.then(data => {
  console.log(data)
})
Share:
198,822
varad
Author by

varad

Updated on January 06, 2021

Comments

  • varad
    varad over 3 years

    I am fetching a URL like this:

    fetch(url, {
      mode: 'no-cors',
      method: method || null,
      headers: {
        'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
        'Content-Type': 'multipart/form-data'
      },
      body: JSON.stringify(data) || null,
    }).then(function(response) {
      console.log(response.status)
      console.log("response");
      console.log(response)
    })
    

    My API expects the data to be of multipart/form-data so I am using content-type of this type... But it is giving me a response with status code 400.

    What's wrong with my code?

  • Matt Pengelly
    Matt Pengelly over 5 years
    Note about the above method, DO NOT supply headers if you do it using FormData because it will override the boundary thats automatically set.
  • Dragos Strugar
    Dragos Strugar over 5 years
    Thanks @MattPengelly! How to set custom headers like Authorization then?
  • RobertMcReed
    RobertMcReed about 5 years
    @DragosStrugar you can still set headers (Authorization included), just don't manually set the Content-Type header if you are using FormData.
  • caot
    caot almost 5 years
    DO NOT supply headers with 'Content-Type' if it's using FormData.
  • konsumer
    konsumer almost 5 years
    In the curl example, you need it. In the FormData example you don't need it, because the browser sends that header for you & also manages all the mime-boundries, which is the point of this solution.
  • Brian Peterson
    Brian Peterson over 4 years
    I think supplying formData directly to the body like this is a much more elegant approach if you don't need to send additional data
  • konsumer
    konsumer over 4 years
    @Brian Peterson: I agree. also it's not too bad even if you have other info to add: formData.set("field","value") for each other value (do it in a loop.)
  • Jnana
    Jnana about 4 years
    const fd = new FormData(); // File to upload. fd.append('file', fileToUpload); fd.append('jsondatakey', 'jsondatavalue'); With this you will be able to send file along with some json data in body.
  • DAVE
    DAVE over 3 years
    What if I need an Authorization?