438

axios POST request is hitting the url on the controller but setting null values to my POJO class, when I go through developer tools in chrome, the payload contains data. What am I doing wrong?

Axios POST Request:

var body = {
    userName: 'Fred',
    userEmail: 'Flintstone@gmail.com'
}

axios({
    method: 'post',
    url: '/addUser',
    data: body
})
.then(function (response) {
    console.log(response);
})
.catch(function (error) {
    console.log(error);
});

Browser Response:

enter image description here

If I set headers as:

headers:{
  Content-Type:'multipart/form-data'
}

The request throws the error

Error in posting multipart/form-data. Content-Type header is missing boundary

If I make the same request in postman it's working fine and sets values to my POJO class.

Can anyone explain how to set boundary or how can I send form data using axios.

AndrewRMillar
  • 608
  • 1
  • 7
  • 17
Srikanth Gowda
  • 6,163
  • 7
  • 19
  • 34

19 Answers19

680

You can post axios data by using FormData() like:

var bodyFormData = new FormData();

And then add the fields to the form you want to send:

bodyFormData.append('userName', 'Fred');

If you are uploading images, you may want to use .append

bodyFormData.append('image', imageFile); 

And then you can use axios post method (You can amend it accordingly)

axios({
  method: "post",
  url: "myurl",
  data: bodyFormData,
  headers: { "Content-Type": "multipart/form-data" },
})
  .then(function (response) {
    //handle success
    console.log(response);
  })
  .catch(function (response) {
    //handle error
    console.log(response);
  });

Related GitHub issue:

Can't get a .post with 'Content-Type': 'multipart/form-data' to work @ axios/axios

BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
Aaqib
  • 9,942
  • 4
  • 21
  • 30
  • 9
    bodyFormData.set is not a function i got this error – Manoj Bhardwaj Apr 20 '18 at 08:59
  • 20
    You need to use append instead of set. – Pratik Singhal Jun 10 '18 at 08:36
  • bodyFormData.append is worked for me too. not sure why `set` not working – Im Batman Aug 26 '18 at 07:12
  • Why did we have to use `append` instead of `set` for uploading images? – meshde Nov 27 '18 at 10:00
  • 4
    Your config object is wrong. It should be: `{ method: 'post', url: 'myurl', data: bodyFormData, headers: {'Content-Type': 'multipart/form-data' } }` – Steve Taylor Mar 30 '19 at 11:20
  • @Aaqib I am trying the same thing but i am getting error. Can you please explain how did you create "imageFile". I guess i am doing this wrong. – Saurabh Kataria Oct 11 '19 at 08:08
  • may I ask you to have a look at an `axios` related question here : https://stackoverflow.com/questions/59470085/vue-js-validation-fails-for-file-upload-in-axios-when-multipart-form-data-used ? – Istiaque Ahmed Dec 24 '19 at 14:26
  • 7
    in nodejs you'll need `npm install --save form-data` – bvdb Mar 08 '21 at 16:27
  • 1
    Latest axios sets the `Content-Type` header automatically with boundary, so better not mess with it. – user1338062 Sep 26 '21 at 09:05
  • 1
    Btw just a quick side note for a thing that took my half an hour: FormData can only handle String and blob values. Therefor it will convert booleans and null values (and also integers) to strings with 'true'/'false' / 'null' / eg. '1337'. You backend may fail when it for example is expecting an integer or null for a field and is handed over a string. – serjoscha Feb 27 '22 at 12:40
  • In `nodejs` you can use `URLSearchParams` instead. For example: `const formData = new URLSearchParams({ param1: 'this', param2: 'is', param3: 'neat', }) ` – Eli Zatlawy May 26 '22 at 07:22
  • install form-data please – Logan Lee Jun 16 '22 at 07:36
  • In my particular case, I needed to add the content-length header too `'Content-Length': formData.getLengthSync(),` – elvin Oct 02 '22 at 00:10
97

In my case I had to add the boundary to the header like the following:

const form = new FormData();
form.append(item.name, fs.createReadStream(pathToFile));

const response = await axios({
    method: 'post',
    url: 'http://www.yourserver.com/upload',
    data: form,
    headers: {
        'Content-Type': `multipart/form-data; boundary=${form._boundary}`,
    },
});

This solution is also useful if you're working with React Native.

Lajos Mészáros
  • 3,756
  • 2
  • 20
  • 26
Luiz Dias
  • 1,947
  • 17
  • 22
  • 6
    This solved my issue when trying to post to imgur's api. Not mentioned anywhere on the docs, but without it you get a 400 Invalid URL response. – Kolby Jan 13 '19 at 07:14
  • 13
    `FormData._boundary` is undefined in both Chrome 76 and Firefox 67, and [axios deletes the Content-Type header anyway](https://github.com/axios/axios/blob/503418718f669fcc674719fd862b355605d7b41f/lib/adapters/xhr.js#L15-L17), so this should have no effect. – ash Aug 16 '19 at 10:18
  • 3
    The boundary part was the only thing that was missing from my code, worked perfeclty in node! – Rafael Moni Sep 24 '19 at 14:12
  • Hi, one problem though this works only in android did you managed to make it work on iOS devices? – HexaCrop Mar 19 '20 at 06:29
  • 1
    @KevinRED Yes, at the time I was actually using React Native with an iOS app... – Luiz Dias Mar 19 '20 at 15:23
  • this will miss import header field like Content-Length, which will get 400 error from some backend service – NGloom May 08 '20 at 16:09
  • fs.createReadStream can only be used on server side not frontend. – Ankush Rishi Jun 19 '20 at 05:34
  • what is `_boundary`? i got undefined! – Oliver D Sep 15 '20 at 19:26
  • 1
    `_boundary` only exists on `form-data` npm module, not on the native FormData in the Browser! And you should use `getBoundary()` instead, or better `getHeaders()`. In the Browser you need only to set ` 'Content-Type': 'multipart/form-data'` without the boundary thing. – Dantio Apr 17 '21 at 19:21
  • Thank you!! This is necessary for Box API. – Brian Fegter Jul 15 '21 at 14:35
  • @LuizDias i am also using react-native. It was working fine before even without boundary, but after i upgraded axios and form-data it is complaining that boundary is missing. None of the solutions is working, formdata._boundary as well as formdata.getHeaders() is giving undefined. – Irfan wani Apr 02 '22 at 03:02
54

Check out querystring.

You can use it as follows:

var querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));
Henry Woody
  • 14,024
  • 7
  • 39
  • 56
cclient
  • 847
  • 7
  • 5
36

Upload (multiple) binary files

Node.js

Things become complicated when you want to post files via multipart/form-data, especially multiple binary files. Below is a working example:

const FormData = require('form-data')
const fs = require('fs')
const path = require('path')

const formData = new FormData()
formData.append('files[]', JSON.stringify({ to: [{ phoneNumber: process.env.RINGCENTRAL_RECEIVER }] }), 'test.json')
formData.append('files[]', fs.createReadStream(path.join(__dirname, 'test.png')), 'test.png')
await rc.post('/restapi/v1.0/account/~/extension/~/fax', formData, {
  headers: formData.getHeaders()
})
  • Instead of headers: {'Content-Type': 'multipart/form-data' } I prefer headers: formData.getHeaders()
  • I use async and await above, you can change them to plain Promise statements if you don't like them
  • In order to add your own headers, you just headers: { ...yourHeaders, ...formData.getHeaders() }

Newly added content below:

Browser

Browser's FormData is different from the NPM package 'form-data'. The following code works for me in browser:

HTML:

<input type="file" id="image" accept="image/png"/>

JavaScript:

const formData = new FormData()

// add a non-binary file
formData.append('files[]', new Blob(['{"hello": "world"}'], { type: 'application/json' }), 'request.json')

// add a binary file
const element = document.getElementById('image')
const file = element.files[0]
formData.append('files[]', file, file.name)
await rc.post('/restapi/v1.0/account/~/extension/~/fax', formData)
Tyler Liu
  • 19,552
  • 11
  • 100
  • 84
19

2020 ES6 way of doing

Having the form in html I binded in data like so:

DATA:

form: {
   name: 'Joan Cap de porc',
   email: 'fake@email.com',
   phone: 2323,
   query: 'cap d\ou'
   file: null,
   legal: false
},

onSubmit:

async submitForm() {
  const formData = new FormData()
  Object.keys(this.form).forEach((key) => {
    formData.append(key, this.form[key])
  })

  try {
    await this.$axios.post('/ajax/contact/contact-us', formData)
    this.$emit('formSent')
  } catch (err) {
    this.errors.push('form_error')
  }
}
Despertaweb
  • 1,672
  • 21
  • 29
18

Using application/x-www-form-urlencoded format in axios

By default, axios serializes JavaScript objects to JSON. To send data in the application/x-www-form-urlencoded format instead, you can use one of the following options.

Browser

In a browser, you can use the URLSearchParams API as follows:

const params = new URLSearchParams();

params.append('param1', 'value1');

params.append('param2', 'value2');

axios.post('/foo', params);

Note that URLSearchParams is not supported by all browsers (see caniuse.com), but there is a polyfill available (make sure to polyfill the global environment).

Alternatively, you can encode data using the qs library:

const qs = require('qs');

axios.post('/foo', qs.stringify({ 'bar': 123 }));

Or in another way (ES6),

import qs from 'qs';

const data = { 'bar': 123 };

const options = {

  method: 'POST',

  headers: { 'content-type': 'application/x-www-form-urlencoded' },

  data: qs.stringify(data),

  url, };

axios(options);
Apostolos
  • 10,033
  • 5
  • 24
  • 39
kartick shaw
  • 915
  • 13
  • 5
7

Even More straightforward:

axios.post('/addUser',{
    userName: 'Fred',
    userEmail: 'Flintstone@gmail.com'
})
.then(function (response) {
    console.log(response);
})
.catch(function (error) {
    console.log(error);
});
thomasL
  • 641
  • 7
  • 7
7
import axios from "axios";
import qs from "qs";   

const url = "https://yourapplicationbaseurl/api/user/authenticate";
    let data = {
      Email: "testuser@gmail.com",
      Password: "Admin@123"
    };
    let options = {
      method: "POST",
      headers: { "content-type": "application/x-www-form-urlencoded" },
      data: qs.stringify(data),
      url
    };
    axios(options)
      .then(res => {
        console.log("yeh we have", res.data);
      })
      .catch(er => {
        console.log("no data sorry ", er);
      });
  };
ABHIJEET KHIRE
  • 2,037
  • 17
  • 10
7

I had the similar issues when using FormData with axios to make calls on https://apps.dev.microsoft.com service and it error-red out with "The request body must contain the following parameter: 'grant_type'"

After reformatting the data from

{
  grant_type: 'client_credentials',
  id: '123',
  secret: '456789'
}

to

"grant_type=client_credentials&id=123&secret=456789"

and the following code worked:

const config: AxiosRequestConfig = {
    method: 'post',
    url: https://apps.dev.microsoft.com/auth,
    data: 'grant_type=client_credentials&id=123&secret=456789',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
    }
};

axios(config)
.then(function (response) {
  console.log(JSON.stringify(response.data));
})
.catch(function (error) {
  console.log(error);
});
s-hunter
  • 24,172
  • 16
  • 88
  • 130
  • 3
    You saved me! For some reason building the object with `FormData` didn't work but when I did something like `data: 'grant_type=client_credentials&id=123&secret=456789',` as you suggested it did the trick! – thodwris Oct 30 '21 at 00:37
  • I have to say that indeed this worked! Postman worked with formdata but it didn't on my project. +1 – Craws Jun 08 '22 at 08:51
6

A boundary (which is used, by the server, to parse the payload) is set when the request is sent. You can't obtain the boundary before making the request. So, a better way to get this is using getBoundary() from your FormData.

var formData = new FormData();
formData.append('userName', 'Fred');
formData.append('file0', fileZero);
formData.append('file1', fileOne);

axios({
  method: "post",
  url: "myurl",
  data: formData,
  headers: {
      'Content-Type':  `multipart/form-data; ${formData.getBoundary()}`,
})
  .then(function (response) {
    //handle success
    console.log(response);
  })
  .catch(function (response) {
    //handle error
    console.log(response);
  });

Nathan Getachew
  • 783
  • 5
  • 16
6

The 2022 way

The Axios documentation hasn't updated yet, but there is a convenient way to to make formdata nowadays, by using the axios.toFormData() method.

Here is its TypeScript definition:

export function toFormData(sourceObj: object, targetFormData?: GenericFormData, options?: FormSerializerOptions): GenericFormData;

Example:

const formData = axios.toFormData({"myField":"myValue"})

const response = await axios({
  method: "post",
  url: "...",
  data: formData,
  headers: { ... }
})

Source:

You can find the following in Axios's Change log

[1.0.0] - 2022-10-04

Added generic TS types for the exposed toFormData helper #4668

Added enhanced toFormData implementation with additional options 4704

louielyl
  • 745
  • 7
  • 9
  • 1
    Note that boolean and numbers must be encoded as string. For example, `axios.toFormData({"foo": true})` will throw `TypeError: data should be a string, Buffer or Uint8Array`. Do `axios.toFormData({"foo": "true}")` instead. – AnonBird Jun 28 '23 at 15:04
4

i needed to calculate the content length aswell

const formHeaders = form.getHeaders();
formHeaders["Content-Length"] = form.getLengthSync()

const config = {headers: formHeaders}

return axios.post(url, form, config)
.then(res => {
    console.log(`form uploaded`)
})
cenobit
  • 81
  • 7
3

I needed to upload many files at once using axios and I struggled for a while because of the FormData API:

// const instance = axios.create(config);

let fd = new FormData();
for (const img of images) { // images is an array of File Object
  fd.append('images', img, img.name); // multiple upload
}

const response = await instance({
  method: 'post',
  url: '/upload/',
  data: fd
})

I did NOT specify the content-type: multipart/form-data header!

1

The above method worked for me but since it was something I needed often, I used a basic method for flat object. Note, I was also using Vue and not REACT

packageData: (data) => {
  const form = new FormData()
  for ( const key in data ) {
    form.append(key, data[key]);
  }
  return form
}

Which worked for me until I ran into more complex data structures with nested objects and files which then let to the following

packageData: (obj, form, namespace) => {
  for(const property in obj) {
    // if form is passed in through recursion assign otherwise create new
    const formData = form || new FormData()
    let formKey

    if(obj.hasOwnProperty(property)) {
      if(namespace) {
        formKey = namespace + '[' + property + ']';
      } else {
        formKey = property;
      }

      // if the property is an object, but not a File, use recursion.
      if(typeof obj[property] === 'object' && !(obj[property] instanceof File)) {
        packageData(obj[property], formData, property);
      } else {
        // if it's a string or a File
      formData.append(formKey, obj[property]);
      }
    }
  }
  return formData;
}
Juan Pablo Ugas
  • 1,085
  • 9
  • 22
  • objectToFormData is undefined and formData is returned outside the for, but is defined inside the for. formData is easy, but what is objectToFormData supposed to be? – Trevor Dec 11 '19 at 18:55
  • I think its supposed to be the name of the function. because it's meant to be recursive, so i assume you can change the `objectToFormData` to `packageData` or vice versa – Raymond Ativie Dec 28 '19 at 03:29
1

For me it worked using axios, typescript and form-data(v4.0.0):

import FormData from "form-data";
import axios from "axios";

async function login() {
  var data = new FormData();
  data.append("User", "asdf");
  const return = await axios.post(
    "https://ptsv2.com/t/1q9gx-1652805776/post", data,
    { headers: data.getHeaders() }
  );
  console.log(return);
}
Bruno Yuzo
  • 469
  • 5
  • 18
1

This should work well when needing to POST x-www-form-urlencoded data using axios from a NodeJS environment. You may need to add an Authorization header to the config.headers object if the endpoint requires authentication.

const config = {
  headers: {
    accept: 'application/json',
    'cache-control': 'no-cache',
    'content-type': 'application/x-www-form-urlencoded'
  }

const params = new URLSearchParams({key1: value1, key2: value2});

return axios
  .post(url, params.toString(), config)
  .then((response) => {
    return response.data;
  })
  .catch((error) => console.error(error));
Andrew Taylor
  • 610
  • 7
  • 26
0

In my case, the problem was that the format of the FormData append operation needed the additional "options" parameter filling in to define the filename thus:

var formData = new FormData();
formData.append(fieldName, fileBuffer, {filename: originalName});

I'm seeing a lot of complaints that axios is broken, but in fact the root cause is not using form-data properly. My versions are:

"axios": "^0.21.1",
"form-data": "^3.0.0",

On the receiving end I am processing this with multer, and the original problem was that the file array was not being filled - I was always getting back a request with no files parsed from the stream.

In addition, it was necessary to pass the form-data header set in the axios request:

        const response = await axios.post(getBackendURL() + '/api/Documents/' + userId + '/createDocument', formData, {
        headers: formData.getHeaders()
    });

My entire function looks like this:

async function uploadDocumentTransaction(userId, fileBuffer, fieldName, originalName) {
    var formData = new FormData();
    formData.append(fieldName, fileBuffer, {filename: originalName});

    try {
        const response = await axios.post(
            getBackendURL() + '/api/Documents/' + userId + '/createDocument',
            formData,
            {
                headers: formData.getHeaders()
            }
        );

        return response;
    } catch (err) {
        // error handling
    }
}

The value of the "fieldName" is not significant, unless you have some receiving end processing that needs it.

ISparkes
  • 1,695
  • 15
  • 15
0

https://www.npmjs.com/package/axios

Its Working

// "content-type": "application/x-www-form-urlencoded", // commit this

import axios from 'axios';

let requestData = {
      username : "abc@gmail.cm",
      password: "123456"
    };
   
    const url = "Your Url Paste Here";

    let options = {
      method: "POST",
      headers: { 
        'Content-type': 'application/json; charset=UTF-8',

        Authorization: 'Bearer ' + "your token Paste Here",
      },
      data: JSON.stringify(requestData),
      url
    };
    axios(options)
      .then(response => {
        console.log("K_____ res :- ", response);
        console.log("K_____ res status:- ", response.status);
      })
      .catch(error => {
        console.log("K_____ error :- ", error);
      });

fetch request

fetch(url, {
    method: 'POST',
    body: JSON.stringify(requestPayload),           
    headers: {
        'Content-type': 'application/json; charset=UTF-8',
        Authorization: 'Bearer ' + token,
    },
})
    // .then((response) => response.json()) .  // commit out this part if response body is empty
    .then((json) => {
        console.log("response :- ", json);
    }).catch((error)=>{
        console.log("Api call error ", error.message);
        alert(error.message);
});
Steven Matthews
  • 9,705
  • 45
  • 126
  • 232
Keshav Gera
  • 10,807
  • 1
  • 75
  • 53
0
 transformRequest: [
  function(data, headers) {
    headers["Content-Type"] = "application/json";
    return JSON.stringify(data);
  }
]

try this, it works

Gururaj H
  • 11
  • 2