116

I'm working on a project that requires https get and post methods. I've got a short https.get function working here...

const https = require("https");

function get(url, callback) {
    "use-strict";
    https.get(url, function (result) {
        var dataQueue = "";    
        result.on("data", function (dataBuffer) {
            dataQueue += dataBuffer;
        });
        result.on("end", function () {
            callback(dataQueue);
        });
    });
}

get("https://example.com/method", function (data) {
    // do something with data
});

My problem is that there's no https.post and I've already tried the http solution here with https module How to make an HTTP POST request in node.js? but returns console errors.

I've had no problem using get and post with Ajax in my browser to the same api. I can use https.get to send query information but I don't think this would be the correct way and I don't think it will work sending files later if I decide to expand.

Is there a small example, with the minimum requirements, to make a https.request what would be a https.post if there was one? I don't want to use npm modules.

Community
  • 1
  • 1
Nova
  • 2,000
  • 3
  • 14
  • 24

4 Answers4

246

For example, like this:

const https = require('https');

var postData = JSON.stringify({
    'msg' : 'Hello World!'
});

var options = {
  hostname: 'posttestserver.com',
  port: 443,
  path: '/post.php',
  method: 'POST',
  headers: {
       'Content-Type': 'application/x-www-form-urlencoded',
       'Content-Length': postData.length
     }
};

var req = https.request(options, (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

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

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

req.write(postData);
req.end();
Rasool Khan
  • 413
  • 6
  • 15
aring
  • 3,422
  • 2
  • 22
  • 29
  • 57
    Nice answer @aring. If you want to send JSON, change the following: ```var postData = JSON.stringify({msg: 'Hello World!'})``` and ```'Content-Type': 'application/json'``` – loonison101 Oct 28 '17 at 12:57
  • 1
    Thanks - I found out the hard way that using require('http') and setting port to 443 in options was not the right way to send a HTTP request. – tschumann Apr 15 '20 at 22:40
  • 4
    I am assuming that `req.write(postData);` would be the posting of the data, would I be correct? I have data coming back from where I posted to, and get outputed data in JSON in the terminal. How would I be able to save that data to a variable from which I got back? – JamLizzy101 Aug 20 '20 at 17:28
  • Might want to check to see if res.statusCode is 200 and if not, take error action. – Robert Oschler Mar 08 '21 at 23:53
  • Given that querystring is nowadays considered legacy code you might want to replace it with URLSearchParams https://nodejs.org/api/url.html#url_class_urlsearchparams – Va5ili5 Oct 16 '21 at 07:18
44

Here's a version slightly different from the accepted answer:

  • @returns Promise
  • You can pass the URL directly (no need to split to hostname, path, port)
  • It handles error HTTP status codes
  • It handles connection timeouts
  • For an alternative content type example, it sends JSON instead of x-www-form-urlencoded
const https = require('https')

function post(url, data) {
  const dataString = JSON.stringify(data)

  const options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Content-Length': dataString.length,
    },
    timeout: 1000, // in ms
  }

  return new Promise((resolve, reject) => {
    const req = https.request(url, options, (res) => {
      if (res.statusCode < 200 || res.statusCode > 299) {
        return reject(new Error(`HTTP status code ${res.statusCode}`))
      }

      const body = []
      res.on('data', (chunk) => body.push(chunk))
      res.on('end', () => {
        const resString = Buffer.concat(body).toString()
        resolve(resString)
      })
    })

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

    req.on('timeout', () => {
      req.destroy()
      reject(new Error('Request time out'))
    })

    req.write(dataString)
    req.end()
  })
}

const res = await post('https://...', data)
Community
  • 1
  • 1
Max Ivanov
  • 5,695
  • 38
  • 52
14

In Node.js 18

Say goodbye to the node-fetch package ,axios and request ,... now the fetch API is available on the global scope by default.

POST REQUEST

app.get('/', (req, res, next) => {
    // Make a post Request.
    
    fetch('https://jsonplaceholder.typicode.com/posts', {
        method: 'POST',
        body: JSON.stringify({
            title: 'foo',
            body: 'bar',
            userId: 1,
        }),
        headers: {
            'Content-type': 'application/json; charset=UTF-8',
        },
    })
        .then((response) => response.json())
        .then((json) => console.log(json))
        .catch(error => {
            console.log(error)
        })

    res.send('Fetch API is available on the global scope by default')
})

GET REQUEST

const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
  const data = await res.json();
  console.log(data);
}

We can make requests as we do in browsers.

For More Information

Abolfazl Roshanzamir
  • 12,730
  • 5
  • 63
  • 79
  • OP said, _"My problem is that there's no https.post"_. So does the fetch API support POST as well? – xpt Feb 02 '23 at 04:48
  • @xpt, You can call all the HTTP verbs such as POST, PATCH, PUT, DELETE, and GET. I tried the POST method It works. – Abolfazl Roshanzamir Feb 02 '23 at 19:56
  • Oh, good to know, Would you post your testing POST method here please, as the question OP has is _"How do I make a https post in Node Js"_ whereas your answer above is HTTP GET only. – xpt Feb 02 '23 at 23:37
6

Thank goodness, node-fetch is here,

everything else is ancient history.

const fetch = require('node-fetch');
// note: use npm install node-fetch@2.0 to be able to use "require"

console.log("trying ...")

let body = {
    "ids": ["4e4e4e4e-4e4e-4e4e-4e4e-4e4e4e4e4e4e"]
};

fetch('https://blahblah.com/blah', {
    method: 'POST',
    body: JSON.stringify(body),
    headers: {
        'accept': 'application/json',
        'x-api-key': 'superamazingsecretcryptostuff',
        'Content-Type': 'application/json'
        // fyi, NO need for content length
    }
})
    .then(res => res.json())
    .then(json => console.log(json))
    .catch (err => console.log(err))

console.log("done....")

Job done.

Fattie
  • 27,874
  • 70
  • 431
  • 719
  • 3
    Isn't the question specifically about doing this *without any 3rd party module* though? – ibz May 27 '22 at 06:33
  • @ibz it's not third party, it's built right in - that's the big news. at last – Fattie May 27 '22 at 12:27
  • I added const `fetch = require('node-fetch');` to the top of my lambda function but caught `Cannot find module 'node-fetch'` ? Any ideas why? – Ethan May 27 '22 at 23:57
  • @Fattie Sorry, my bad. Seems indeed it has been finally merged into Node! I didn't know, and your note `// note: use npm install` made me think you are trying to use it as an external package. Great news! PS: I would now upvote but SO won't let me unless you edit your answer. Perhaps just edit and add a comment saying `// included as of node v17.5.0` just to be clear for all? – ibz May 30 '22 at 07:36
  • 1
    i only realized it thanks to SO ! – Fattie May 30 '22 at 10:57
  • I assume this code is compatible with the browser-based "fetch", right? So essentially the same code will be able to be used in node.js and in the browser to make an external request, which is pretty neat! – ibz May 30 '22 at 12:24
  • @ibz unfortunately I know almost nothing about browser tech. (We do apps and servers! :) ) So I leave that to others. ("Does this have to do with html?!" :) ) – Fattie May 30 '22 at 12:36