axios post request to send form data
Asked Answered
O

21

453

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: '[email protected]'
}

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.

Orthodontics answered 4/12, 2017 at 9:29 Comment(1)
What does this have to do with react and redux? Can we just make it generic JS?Bedchamber
B
694

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

Bekki answered 4/12, 2017 at 10:1 Comment(13)
bodyFormData.set is not a function i got this errorTightwad
You need to use append instead of set.Deceleron
bodyFormData.append is worked for me too. not sure why set not workingSymphonia
Why did we have to use append instead of set for uploading images?Theocrasy
Your config object is wrong. It should be: { method: 'post', url: 'myurl', data: bodyFormData, headers: {'Content-Type': 'multipart/form-data' } }Orit
@Bekki 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.Mcdaniel
may I ask you to have a look at an axios related question here : #59470585 ?Froze
in nodejs you'll need npm install --save form-dataAnaphase
Latest axios sets the Content-Type header automatically with boundary, so better not mess with it.Harneen
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.Brainwashing
In nodejs you can use URLSearchParams instead. For example: const formData = new URLSearchParams({ param1: 'this', param2: 'is', param3: 'neat', }) Bumbledom
install form-data pleaseCloudberry
In my particular case, I needed to add the content-length header too 'Content-Length': formData.getLengthSync(),Awesome
E
96

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.

Evaevacuant answered 2/11, 2018 at 21:43 Comment(11)
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.Sievert
FormData._boundary is undefined in both Chrome 76 and Firefox 67, and axios deletes the Content-Type header anyway, so this should have no effect.Grade
The boundary part was the only thing that was missing from my code, worked perfeclty in node!Weismannism
Hi, one problem though this works only in android did you managed to make it work on iOS devices?Equinox
@KevinRED Yes, at the time I was actually using React Native with an iOS app...Evaevacuant
this will miss import header field like Content-Length, which will get 400 error from some backend serviceHamelin
fs.createReadStream can only be used on server side not frontend.Buhler
what is _boundary? i got undefined!Valorize
_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.Desultory
Thank you!! This is necessary for Box API.Hauteloire
@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.Wiesbaden
O
53

Check out querystring.

You can use it as follows:

var querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));
Oath answered 2/8, 2018 at 7:59 Comment(5)
This is even better in a node environmentReinwald
If you have nested objects in your data, 'querystring' may not work as expected. In that case, you can use 'qs' module to stringify the data.Satiated
This is not form data. This is a url-encoded form format.Forejudge
The querystring package has been deprecated for some reasonHyperaesthesia
Querystring is deprecated. This is the current method: const data = new URLSearchParams(dataObject).toString(); Then post that data object.Tuning
I
37

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)
Inapproachable answered 23/5, 2018 at 7:7 Comment(9)
Thank you so much for this example, had a hard time figuring out why multiple file upload was not working.Reremouse
I'm not an expert, but in my case I have managed to avoid these complications (concat-stream, async and await) for multiple file upload by using for(var x = 0; x<this.state.files.length; x++) { formData.append('files[]', this.state.files[x]) } so I can submit using axios.post(url, formData, config)Produce
@Produce thanks, it works for me. I've updated my answer.Inapproachable
@TylerLong I can't find any getHeaders method in FormData API. developer.mozilla.org/en-US/docs/Web/API/FormDataPentadactyl
headers: formData.getHeaders() is what got it working for me. Thanks.Levon
formData.getHeaders() works but what about token we need to add???Jipijapa
@GvsAkhil check my latest update about how to add your own headers.Inapproachable
This is not working with mutler on node.js side when u have binary fileFaunia
@ИгорТашевски Please report the issue to the multer project.Inapproachable
M
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);
Monkey answered 28/2, 2020 at 19:26 Comment(0)
N
18

2020 ES6 way of doing

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

DATA:

form: {
   name: 'Joan Cap de porc',
   email: '[email protected]',
   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')
  }
}
Narvaez answered 21/4, 2020 at 14:25 Comment(0)
D
8

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

Dehlia answered 4/3, 2023 at 2:45 Comment(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.Airs
M
6

Even More straightforward:

axios.post('/addUser',{
    userName: 'Fred',
    userEmail: '[email protected]'
})
.then(function (response) {
    console.log(response);
})
.catch(function (error) {
    console.log(error);
});
Montgolfier answered 12/7, 2019 at 10:32 Comment(1)
Yes, as it seems, if there are no file uploads, this is the easiest way.Transport
V
6
import axios from "axios";
import qs from "qs";   

const url = "https://yourapplicationbaseurl/api/user/authenticate";
    let data = {
      Email: "[email protected]",
      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);
      });
  };
Vibratory answered 18/6, 2020 at 17:45 Comment(0)
G
6

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);
});
Gasparo answered 28/10, 2021 at 21:2 Comment(2)
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!Stormi
I have to say that indeed this worked! Postman worked with formdata but it didn't on my project. +1Thorstein
T
5

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);
  });

Tapir answered 1/6, 2022 at 23:23 Comment(1)
It worked for me with just 'Content-Type': 'multipart/form-data'Wineglass
T
3

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`)
})
Tupiguarani answered 5/2, 2021 at 21:31 Comment(1)
WIthout this I couldn't get the response. ThanksCrackling
E
2

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!

Experienced answered 12/8, 2021 at 10:40 Comment(0)
H
2

On newest axios version you can send a post form data by using:

axios.postForm(url, data);

It will have the same result as creating one by one in form instance:

var bodyFormData = new FormData();
bodyFormData.append("abc", "xyz");

You can view more about it in axios Docs: https://axios-http.com/docs/multipart

Halfsole answered 28/11, 2023 at 14:39 Comment(0)
T
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));
Tuning answered 17/5, 2022 at 17:46 Comment(0)
C
1

Axios has it built in.

axios.postForm('https://localhost', {
  my_field: 'my value',
});
Cinthiacintron answered 30/1 at 13:45 Comment(0)
P
0

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;
}
Prairial answered 3/8, 2018 at 13:2 Comment(2)
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?Poltroonery
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 versaBespangle
R
0

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);
}
Reasonless answered 17/5, 2022 at 17:0 Comment(0)
O
-1

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.

Ocieock answered 13/1, 2021 at 11:12 Comment(1)
And what about browser formData object? Axios not working well with browser form-dataFaunia
N
-2
 transformRequest: [
  function(data, headers) {
    headers["Content-Type"] = "application/json";
    return JSON.stringify(data);
  }
]

try this, it works

Naos answered 13/8, 2021 at 11:11 Comment(0)
S
-3

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

Its Working

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

import axios from 'axios';

let requestData = {
      username : "[email protected]",
      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);
});
Stuff answered 21/1, 2021 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.