Pass Data to Service in Axios

This question seems to come up often enough yet I cannot seem to find a canonical answer so here goes…

When performing AJAX requests from a browser (via fetch or XMLHttpRequest), the runtime knows what to do for certain request body formats and will automatically set the appropriate Content-type header

  • If the request body is a FormData instance, the Content-type will be set to multipart/form-data and will also include the appropriate mime boundary tokens from the data instance.

    All of these examples will post the data as multipart/form-data with appropriate mime boundary tokens

    const body = new FormData();
    body.append("foo", "foo");
    body.append("bar", "bar");
    
    // fetch
    fetch(url, { method: "POST", body });
    
    // XMLHttpRequest
    const xhr = new XMLHttpRequest();
    xhr.open("POST", url);
    xhr.send(body);
    
    // Axios
    axios.post(url, body);
    
  • If the request body is a URLSearchParams instance, the Content-type will be set to application/x-www-form-urlencoded

    All of these examples will post the data as application/x-www-form-urlencoded

    const body = new URLSearchParams({ foo: "foo", bar: "bar" });
    // serialises to "foo=foo&bar=bar"
    
    // fetch
    fetch(url, { method: "POST", body });
    
    // XMLHttpRequest
    const xhr = new XMLHttpRequest();
    xhr.open("POST", url);
    xhr.send(body);
    
    // Axios
    axios.post(url, body);
    

You only need to manually set the content-type if you intend to send string data in a particular format, eg text/xml, application/json, etc since the runtime cannot infer the type from the data.

const body = JSON.stringify({ foo: "foo", bar: "bar" });

// fetch
fetch(url, {
  method: "POST",
  headers: {
    "content-type": "application/json",
  },
  body
});

// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(body);

On Axios

Axios provides defaults of Accept: application/json and Content-type: application/json for POST, PUT and PATCH requests. It will also automatically stringify JavaScript data structures passed into the data parameter so you only need minimal configuration when dealing with JSON APIs

// no extra headers, no JSON.stringify()
axios.post(url, { foo: "foo", bar: "bar" })

Under the hood, Axios uses XMLHttpRequest so the specifications for FormData and URLSearchParams also apply.

Axios 0.27.1 is broken

This specific version of Axios is unable to make a proper request with FormData. Do not use it!

NodeJS

When using Axios from the backend, it will not infer Content-type headers from FormData instances. You can work around this using a request interceptor.

axios.interceptors.request.use(config => {
  if (config.data instanceof FormData) {
    Object.assign(config.headers, config.data.getHeaders());
  }
  return config;
}, null, { synchronous: true });

See https://github.com/axios/axios#form-data


On jQuery $.ajax()

jQuery’s $.ajax() method (and convenience methods like $.post()) default to sending request body payloads as application/x-www-form-urlencoded. JavaScript data structures will be automatically serialised using jQuery.param() unless told not to. If you want the browser to automatically set the Content-type header based on the body format, you also need to configure that in the options

const body = new FormData()
body.append("foo", "foo")
body.append("bar", "bar")

$.ajax({
  url,
  method: "POST",
  data: body,
  contentType: false, // let the browser figure it out
  processData: false  // don't attempt to serialise data
})

Leave a Comment