How to send urlencoded data using Axios

By

Learn how to send urlencoded data with Axios: pass a URLSearchParams object, or set the x-www-form-urlencoded header and let Axios 1.x serialize nested objects.

~~~

To send urlencoded data using Axios, pass a URLSearchParams object as data. Axios 1.x detects that type and sends it as application/x-www-form-urlencoded for you. For nested objects, set the content-type header and Axios serializes the object with bracket notation. You only need qs on Axios versions older than 1.0.

I had this problem: an API I had to call from a Node.js app was only accepting data using the urlencoded format.

What is urlencoded data?

It’s the format HTML forms use when they submit: key/value pairs separated by =, joined by &:

item1=value1&item2=value2

When you pass a plain JavaScript object as data, Axios serializes it to JSON by default. An API that expects form data will reject that body, or parse it into nothing.

The modern way: URLSearchParams

In browsers and modern Node.js, build the body with URLSearchParams:

const axios = require('axios')

axios({
  method: 'post',
  url: 'https://my-api.com',
  data: new URLSearchParams({
    item1: 'value1',
    item2: 'value2'
  })
})

Axios sees the URLSearchParams instance and sets the right content type. No extra package for flat key/value pairs.

With ES Modules:

import axios from 'axios'

await axios.post(
  'https://my-api.com',
  new URLSearchParams({
    item1: 'value1',
    item2: 'value2'
  })
)

Nested objects

URLSearchParams is flat. Nested objects need the bracket notation servers like PHP and Rails understand: user[name]=Flavio.

Since Axios 1.0, you get that by passing a plain object and setting the content-type header yourself. Axios sees the header and serializes the object into urlencoded format:

axios({
  method: 'post',
  url: 'https://my-api.com',
  data: {
    user: { name: 'Flavio' }
  },
  headers: {
    'content-type': 'application/x-www-form-urlencoded'
  }
})

The body becomes user%5Bname%5D=Flavio, the encoded form of user[name]=Flavio.

On older Axios versions: qs

Axios 0.x doesn’t do that serialization. There, use the qs library:

npm install qs

Stringify the data and set the header:

const qs = require('qs')
const axios = require('axios')

axios({
  method: 'post',
  url: 'https://my-api.com',
  data: qs.stringify({
    user: { name: 'Flavio' }
  }),
  headers: {
    'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
  }
})

qs.stringify({ user: { name: 'Flavio' } }) gives the same user%5Bname%5D=Flavio string.

A pitfall to avoid

If you pass a plain object as data and don’t set the header, Axios sends a JSON body. An API that expects form data can’t parse it.

Pass URLSearchParams, or set the content-type header so Axios serializes the object for you. If the API responds with an error saying a required field is missing even though you’re sending it, this mismatch is the first thing to check.

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about js: