0

I am trying to call a REST API from node using node-rest-client. In the event that my call returns an error, I want to catch the error and report it to the caller.

I am trying this with Postman, unfortunately this only works once. When I press send the second time, my node.js program crashes with the error "Can't set headers after they are sent."

I am new at node.js, so any help is highly appreciated!

//app stuff
const client_id = "x";
const client_secret = "y";
const callback = "https://myurl;

// Basic Setup
var http     = require('http'),
    express  = require('express'),
    mysql    = require('mysql'),
    parser   = require('body-parser'),
    Client   = require('node-rest-client').Client;

var client = new Client();

// Setup express
var app = express();
app.use(parser.json());
app.use(parser.urlencoded({ extended: true }));
app.set('port', process.env.PORT || 5000);

// Set default route
app.get('/', function (req, res) {
    res.send('<html><body><p>Welcome to Bank API Wrapper</p></body></html>');
});

app.post('/authorize', function (req,res) {
    var response = [];

    if (typeof req.body.code !== 'undefined' && typeof req.body.state !== 'undefined' ){
        var code = req.body.code, state = req.body.state;

        //conversion to base64 because citi api wants it this way
        var authorization = "Basic " + Buffer.from(client_id + ":" + client_secret).toString('base64');

        var args = {
            data:{"grant_type":"authorization_code","code":code,"redirect_uri":callback},
            headers:{"Authorization":authorization,"Content-Type":"application/x-www-form-urlencoded"} 
        };

        //get access and refresh token
        client.post("https://sandbox.apihub.citi.com/gcb/api/authCode/oauth2/token/sg/gcb", args, function (citidata, citiresponse) {
            //console.log(citidata);
            //console.log(citiresponse);
        });

        client.on('error', function (err) {
            response.push({'result' : 'error', 'msg' : 'unauthorized access'});
            res.setHeader('Content-Type', 'application/json');
            res.status(200).send(JSON.stringify(response));
        });
    } 
    else {
        response.push({'result' : 'error', 'msg' : 'Please fill required details'});
        res.setHeader('Content-Type', 'application/json');
        res.status(200).send(JSON.stringify(response));
    }
});


// Create server
http.createServer(app).listen(app.get('port'), function(){
    console.log('Server listening on port ' + app.get('port'));
});
Jackson Ng
  • 368
  • 2
  • 16
  • The program has no problem with the "Please fill required details" part. The problem is with the section that says client.on('error'. It works only once. After that, I get the error "Can't set headers after they are sent." – Jackson Ng Oct 21 '17 at 14:01

1 Answers1

1

You've got this:

client.on('error', function (err) {

This register an error handler on the client but it never gets removed. The client is shared between requests so any errors on subsequent requests will still fire the old error handlers.

Instead you can listen for an error on the request. Something like this:

var request = client.post("...

request.on('error', function(err) {
    // handle error
});

See https://www.npmjs.com/package/node-rest-client#error-handling

skirtle
  • 27,868
  • 4
  • 42
  • 57
  • Tried it and got this. Only client.on('error.").. catches the error. events.js:165 throw err; ^ Error: Uncaught, unspecified "error" event. (Error parsing response. response: [{"type":"bad request","code":"400".... – Jackson Ng Oct 21 '17 at 14:12
  • I solved it by moving var client = new Client(); within app.post. Thanks! Your comment that client is shared between requests is extremely useful! Thank you! – Jackson Ng Oct 21 '17 at 14:21
  • 1
    @JacksonNg I tested it myself and using a request error handler as I described does catch the error. It shouldn't be necessary to move the `Client` creation inside `app.post`. – skirtle Oct 21 '17 at 14:31
  • funny it didn't work for me though. It seems that client.on caught the error but request.on doesn't. – Jackson Ng Oct 21 '17 at 14:38