Skip to content
FLAVIO COPES
flaviocopes.com

Make an HTTP POST request using Node

By

Learn how to make an HTTP POST request in Node.js using built-in fetch, the Axios library, or the low-level https module with https.request().

~~~

There are many ways to perform an HTTP POST request in Node, depending on the abstraction level you want to use.

Since Node 18, the fetch function is built in, no install required. Today this is the way I recommend:

const res = await fetch('https://yourwebsite.com/todos', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ todo: 'Buy the milk' }),
})

console.log(`status: ${res.status}`)
console.log(await res.json())

Save this as post.mjs and run it with node post.mjs (the .mjs extension enables top-level await). A successful call logs status: 200, or 201 when the API creates a resource.

Note the two things fetch makes you do yourself: turn the object into a string with JSON.stringify(), and set the Content-Type header. Forget the header and many servers refuse to parse the body, so you get a confusing 400 back.

Before fetch was built in, the most popular approach was the Axios library:

const axios = require('axios')

axios
  .post('/todos', {
    todo: 'Buy the milk',
  })
  .then((res) => {
    console.log(`statusCode: ${res.status}`)
    console.log(res)
  })
  .catch((error) => {
    console.error(error)
  })

Axios serializes the object and sets the JSON header for you. It’s still a fine choice, especially in codebases that already use it.

You will also find older code using the Request library. It was hugely popular for years, but it is deprecated and unmaintained, so don’t pick it for new projects:

const request = require('request')

request.post(
  '/todos',
  {
    json: {
      todo: 'Buy the milk',
    },
  },
  (error, res, body) => {
    if (error) {
      console.error(error)
      return
    }
    console.log(`statusCode: ${res.statusCode}`)
    console.log(body)
  }
)

Using the standard https module

A POST request is possible just using the Node standard modules, although it’s more verbose than the preceding options:

const https = require('https')

const data = JSON.stringify({
  todo: 'Buy the milk',
})

const options = {
  hostname: 'yourwebsite.com',
  port: 443,
  path: '/todos',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': data.length,
  },
}

const req = https.request(options, (res) => {
  console.log(`statusCode: ${res.statusCode}`)

  res.on('data', (d) => {
    process.stdout.write(d)
  })
})

req.on('error', (error) => {
  console.error(error)
})

req.write(data)
req.end()

Here you build the request piece by piece: req.write(data) queues the body, and nothing goes over the wire until you call req.end(). Forgetting req.end() is the classic mistake with this API — the program just hangs, waiting, with no error to point you at the cause.

To quickly test an endpoint like this from the terminal, I built a free route to curl tool that generates the curl (or fetch) command from a route description.

Tagged: Node.js · All topics
~~~

Related posts about node: