227

How can I make an HTTP request from within Node.js or Express.js? I need to connect to another service. I am hoping the call is asynchronous and that the callback contains the remote server's response.

Ed The ''Pro''
  • 875
  • 10
  • 22
Travis Parks
  • 8,435
  • 12
  • 52
  • 85
  • In Node.js 18, the fetch API is available on the global scope by default https://stackoverflow.com/questions/6158933/how-is-an-http-post-request-made-in-node-js/71991867#71991867 – Abolfazl Roshanzamir Apr 24 '22 at 20:04

13 Answers13

243

Here is a snippet of some code from a sample of mine. It's asynchronous and returns a JSON object. It can do any form of GET request.

Note that there are more optimal ways (just a sample) - for example, instead of concatenating the chunks you put into an array and join it etc... Hopefully, it gets you started in the right direction:

const http = require('http');
const https = require('https');

/**
 * getJSON:  RESTful GET request returning JSON object(s)
 * @param options: http options object
 * @param callback: callback to pass the results JSON object(s) back
 */

module.exports.getJSON = (options, onResult) => {
  console.log('rest::getJSON');
  const port = options.port == 443 ? https : http;

  let output = '';

  const req = port.request(options, (res) => {
    console.log(`${options.host} : ${res.statusCode}`);
    res.setEncoding('utf8');

    res.on('data', (chunk) => {
      output += chunk;
    });

    res.on('end', () => {
      let obj = JSON.parse(output);

      onResult(res.statusCode, obj);
    });
  });

  req.on('error', (err) => {
    // res.send('error: ' + err.message);
  });

  req.end();
};

It's called by creating an options object like:

const options = {
  host: 'somesite.com',
  port: 443,
  path: '/some/path',
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  }
};

And providing a callback function.

For example, in a service, I require the REST module above and then do this:

rest.getJSON(options, (statusCode, result) => {
  // I could work with the resulting HTML/JSON here. I could also just return it
  console.log(`onResult: (${statusCode})\n\n${JSON.stringify(result)}`);

  res.statusCode = statusCode;

  res.send(result);
});

UPDATE

If you're looking for async/await (linear, no callback), promises, compile time support and intellisense, we created a lightweight HTTP and REST client that fits that bill:

Microsoft typed-rest-client

Ed The ''Pro''
  • 875
  • 10
  • 22
bryanmac
  • 38,941
  • 11
  • 91
  • 99
  • @bryanmac can you please send/add the complete sample? – StErMi Jan 17 '13 at 09:55
  • 1
    @bryanmac with your permission I would like to use this code grunt plugin i'm currently building. Not sure when but it would be made open sourced when completed. – JeffH Apr 25 '13 at 15:52
  • @JeffH - no problem. no rocket science here, standard http calls :) – bryanmac Jun 12 '13 at 02:02
  • 3
    try request module .. it is much simpler http://www.sitepoint.com/making-http-requests-in-node-js/ – saurshaz Aug 24 '13 at 05:33
  • 6
    yes - request module is simple but this is lower level showing what libraries like request module is doing. If you need lower level control or http requests (showing progress on large downloads etc...), this shows how it's done. – bryanmac Aug 24 '13 at 16:50
  • @bryanmac Could you please provide the detailed documentation link about available options? searched for `joyent node https module`, but, not found! – Midhun KM Aug 03 '16 at 06:32
  • Is it this one? https://github.com/joyent/node-http-signature I was trying to figure out is there any other options for specifying query params, or just add the big string in `path`. – Midhun KM Aug 03 '16 at 06:35
  • 1
    @KrIsHnA - node has a querystring object: https://nodejs.org/api/querystring.html and url object https://nodejs.org/docs/latest/api/url.html – bryanmac Aug 04 '16 at 21:01
  • Cool, but why is node_modules part of the repo!? – timhc22 Sep 27 '16 at 14:36
  • I'm trying to run this code but I keep getting the error `res` is undefined when inside of my `onResult` call. – Cameron May 26 '17 at 04:23
  • How did you 'require' the module? – Benjamin Dec 03 '18 at 10:03
  • would you please tell me what in onResult and how it works? – Amrmsmb Jun 30 '23 at 05:30
109

Try using the simple http.get(options, callback) function in node.js:

var http = require('http');
var options = {
  host: 'www.google.com',
  path: '/index.html'
};

var req = http.get(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));

  // Buffer the body entirely for processing as a whole.
  var bodyChunks = [];
  res.on('data', function(chunk) {
    // You can process streamed parts here...
    bodyChunks.push(chunk);
  }).on('end', function() {
    var body = Buffer.concat(bodyChunks);
    console.log('BODY: ' + body);
    // ...and/or process the entire body here.
  })
});

req.on('error', function(e) {
  console.log('ERROR: ' + e.message);
});

There is also a general http.request(options, callback) function which allows you to specify the request method and other request details.

Lucas
  • 16,930
  • 31
  • 110
  • 182
maerics
  • 151,642
  • 46
  • 269
  • 291
  • Where's the content of the server's response that the OP asked for? – Dan Dascalescu Dec 20 '13 at 13:55
  • Thanks for the update. Looks like there's a need for an 'end' handler to concatenate the chunks then. Which basically amounts to @bryanmac's answer? – Dan Dascalescu Dec 20 '13 at 15:04
  • @DanDascalescu: ya, if you want to process the body as a whole (which is likely) then you probably want to buffer it and process on 'end'. I'll update my answer too for completeness. – maerics Dec 20 '13 at 15:30
  • sorry, i can't figure out what parameters callback is called with...how can i get body and where is the reference for parameters and properties of that parameters. – Muhammad Umer Feb 23 '15 at 00:27
  • @maerics How can I use this `GET` request if I have this url? `graph.facebook.com/debug_token? input_token={token-to-inspect} &access_token={app-token-or-admin-token}` ? – frank17 Mar 24 '19 at 00:15
  • What constraints compelled the Node team to choose not to include a convenience for concatenating the body? Nearly every https request snippet on the web contains a variation of this cumbersome concatenation, many of which are broken, inefficient or otherwise less-than-optimal. – Kevin McDonough Jul 07 '23 at 18:49
73

Request and Superagent are pretty good libraries to use.

note: request is deprecated, use at your risk!

Using request:

var request=require('request');

request.get('https://someplace',options,function(err,res,body){
  if(err) //TODO: handle err
  if(res.statusCode === 200 ) //etc
  //TODO Do something with response
});
staackuser2
  • 12,172
  • 4
  • 42
  • 40
37

You can also use Requestify, a really cool and very simple HTTP client I wrote for nodeJS + it supports caching.

Just do the following for GET method request:

var requestify = require('requestify');

requestify.get('http://example.com/api/resource')
  .then(function(response) {
      // Get the response body (JSON parsed or jQuery object for XMLs)
      response.getBody();
  }
);
ranm8
  • 1,085
  • 10
  • 10
14

This version is based on the initially proposed by bryanmac function which uses promises, better error handling, and is rewritten in ES6.

let http = require("http"),
    https = require("https");

/**
* getJSON:  REST get request returning JSON object(s)
* @param options: http options object
*/
exports.getJSON = function (options) {
    console.log('rest::getJSON');
    let reqHandler = +options.port === 443 ? https : http;

    return new Promise((resolve, reject) => {
        let req = reqHandler.request(options, (res) => {
            let output = '';
            console.log('rest::', options.host + ':' + res.statusCode);
            res.setEncoding('utf8');

            res.on('data', function (chunk) {
                output += chunk;
            });

            res.on('end', () => {
                try {
                    let obj = JSON.parse(output);
                    // console.log('rest::', obj);
                    resolve({
                        statusCode: res.statusCode,
                        data: obj
                    });
                }
                catch (err) {
                    console.error('rest::end', err);
                    reject(err);
                }
            });
        });

        req.on('error', (err) => {
            console.error('rest::request', err);
            reject(err);
        });

        req.end();
    });
};

As a result you don't have to pass in a callback function, instead getJSON() returns a promise. In the following example the function is used inside of an ExpressJS route handler

router.get('/:id', (req, res, next) => {
    rest.getJSON({
        host: host,
        path: `/posts/${req.params.id}`,
        method: 'GET'
    }).then(({ statusCode, data }) => {
        res.json(data);
    }, (error) => {
        next(error);
    });
});

On error it delegates the error to the server error handling middleware.

rofrol
  • 14,438
  • 7
  • 79
  • 77
maqduni
  • 459
  • 7
  • 8
  • 1
    Yes,this example is showing how to do it inside an Express `get` route definition, which many posts here are lacking. – Micros Dec 21 '18 at 10:08
  • In your 2nd code regarding this `express example`, it seems like it is the server code whereas the first code is client code. What is `rest.getJSON` in 2nd code? Is it a typo and should be `res.getJSON`? – Timo Dec 28 '21 at 14:31
  • `rest` is the object that's exported in the first code block. Therefore in order to access `getJSON()` you can either import the entire `rest` object or just import `getJSON` from the first file. They both are server side excerpts. – maqduni Dec 28 '21 at 19:31
9

Unirest is the best library I've come across for making HTTP requests from Node. It's aiming at being a multiplatform framework, so learning how it works on Node will serve you well if you need to use an HTTP client on Ruby, PHP, Java, Python, Objective C, .Net or Windows 8 as well. As far as I can tell the unirest libraries are mostly backed by existing HTTP clients (e.g. on Java, the Apache HTTP client, on Node, Mikeal's Request libary) - Unirest just puts a nicer API on top.

Here are a couple of code examples for Node.js:

var unirest = require('unirest')

// GET a resource
unirest.get('http://httpbin.org/get')
  .query({'foo': 'bar'})
  .query({'stack': 'overflow'})
  .end(function(res) {
    if (res.error) {
      console.log('GET error', res.error)
    } else {
      console.log('GET response', res.body)
    }
  })

// POST a form with an attached file
unirest.post('http://httpbin.org/post')
  .field('foo', 'bar')
  .field('stack', 'overflow')
  .attach('myfile', 'examples.js')
  .end(function(res) {
    if (res.error) {
      console.log('POST error', res.error)
    } else {
      console.log('POST response', res.body)
    }
  })

You can jump straight to the Node docs here

Brian Beckett
  • 4,742
  • 6
  • 33
  • 52
4

Check out httpreq: it's a node library I created because I was frustrated there was no simple http GET or POST module out there ;-)

Sam
  • 5,375
  • 2
  • 45
  • 54
4

Check out shred. It's a node HTTP client created and maintained by spire.io that handles redirects, sessions, and JSON responses. It's great for interacting with rest APIs. See this blog post for more details.

Jonathan McIntire
  • 2,665
  • 23
  • 26
3

For anyone who looking for a library to send HTTP requests in NodeJS, axios is also a good choice. It supports Promises :)

Install (npm): npm install axios

Example GET request:

const axios = require('axios');

axios.get('https://google.com')
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })

Github page


Update 10/02/2022

Node.js integrates fetch in v17.5.0 in experimental mode. Now, you can use fetch to send requests just like you do on the client-side. For now, it is an experimental feature so be careful. enter image description here

Đăng Khoa Đinh
  • 5,038
  • 3
  • 15
  • 33
0

If you just need to make simple get requests and don't need support for any other HTTP methods take a look at: simple-get:

var get = require('simple-get');

get('http://example.com', function (err, res) {
  if (err) throw err;
  console.log(res.statusCode); // 200
  res.pipe(process.stdout); // `res` is a stream
});
benjiman
  • 3,888
  • 4
  • 29
  • 44
0

Use reqclient: not designed for scripting purpose like request or many other libraries. Reqclient allows in the constructor specify many configurations useful when you need to reuse the same configuration again and again: base URL, headers, auth options, logging options, caching, etc. Also has useful features like query and URL parsing, automatic query encoding and JSON parsing, etc.

The best way to use the library is create a module to export the object pointing to the API and the necessary configurations to connect with:

Module client.js:

let RequestClient = require("reqclient").RequestClient

let client = new RequestClient({
  baseUrl: "https://myapp.com/api/v1",
  cache: true,
  auth: {user: "admin", pass: "secret"}
})

module.exports = client

And in the controllers where you need to consume the API use like this:

let client = require('client')
//let router = ...

router.get('/dashboard', (req, res) => {
  // Simple GET with Promise handling to https://myapp.com/api/v1/reports/clients
  client.get("reports/clients")
    .then(response => {
       console.log("Report for client", response.userId)  // REST responses are parsed as JSON objects
       res.render('clients/dashboard', {title: 'Customer Report', report: response})
    })
    .catch(err => {
      console.error("Ups!", err)
      res.status(400).render('error', {error: err})
    })
})

router.get('/orders', (req, res, next) => {
  // GET with query (https://myapp.com/api/v1/orders?state=open&limit=10)
  client.get({"uri": "orders", "query": {"state": "open", "limit": 10}})
    .then(orders => {
      res.render('clients/orders', {title: 'Customer Orders', orders: orders})
    })
    .catch(err => someErrorHandler(req, res, next))
})

router.delete('/orders', (req, res, next) => {
  // DELETE with params (https://myapp.com/api/v1/orders/1234/A987)
  client.delete({
    "uri": "orders/{client}/{id}",
    "params": {"client": "A987", "id": 1234}
  })
  .then(resp => res.status(204))
  .catch(err => someErrorHandler(req, res, next))
})

reqclient supports many features, but it has some that are not supported by other libraries: OAuth2 integration and logger integration with cURL syntax, and always returns native Promise objects.

Mariano Ruiz
  • 4,314
  • 2
  • 38
  • 34
0

If you ever need to send GET request to an IP as well as a Domain (Other answers did not mention you can specify a port variable), you can make use of this function:

function getCode(host, port, path, queryString) {
    console.log("(" + host + ":" + port + path + ")" + "Running httpHelper.getCode()")

    // Construct url and query string
    const requestUrl = url.parse(url.format({
        protocol: 'http',
        hostname: host,
        pathname: path,
        port: port,
        query: queryString
    }));

    console.log("(" + host + path + ")" + "Sending GET request")
    // Send request
    console.log(url.format(requestUrl))
    http.get(url.format(requestUrl), (resp) => {
        let data = '';

        // A chunk of data has been received.
        resp.on('data', (chunk) => {
            console.log("GET chunk: " + chunk);
            data += chunk;
        });

        // The whole response has been received. Print out the result.
        resp.on('end', () => {
            console.log("GET end of response: " + data);
        });

    }).on("error", (err) => {
        console.log("GET Error: " + err);
    });
}

Don't miss requiring modules at the top of your file:

http = require("http");
url = require('url')

Also bare in mind that you may use https module for communicating over secured network. so these two lines would change:

https = require("https");
...
https.get(url.format(requestUrl), (resp) => { ......
AmiNadimi
  • 5,129
  • 3
  • 39
  • 55
-1
## you can use request module and promise in express to make any request ##
const promise                       = require('promise');
const requestModule                 = require('request');

const curlRequest =(requestOption) =>{
    return new Promise((resolve, reject)=> {
        requestModule(requestOption, (error, response, body) => {
            try {
                if (error) {
                    throw error;
                }
                if (body) {

                    try {
                        body = (body) ? JSON.parse(body) : body;
                        resolve(body);
                    }catch(error){
                        resolve(body);
                    }

                } else {

                    throw new Error('something wrong');
                }
            } catch (error) {

                reject(error);
            }
        })
    })
};

const option = {
    url : uri,
    method : "GET",
    headers : {

    }
};


curlRequest(option).then((data)=>{
}).catch((err)=>{
})
izhar ahmad
  • 81
  • 1
  • 2