Bartlomiej Lewandowski
Bartlomiej Lewandowski

Reputation: 11180

Export a variable which is a result of an asynchronous function call

I'm creating an app that will use the https://github.com/vpulim/node-soap to communicate with a soap server.

I would like to create a client component which I will forward the necessary methods to the soap-client created with this module.

I'm having trouble to return an object that will use this client, since the client is created asynchronously.

var soap = require('soap');
var url = 'http://someurl?wsdl';

soap.createClient(url, function(err, client) {
    if (err) {
        console.log(err);
        return;
    }
    console.log(client.describe());
    // I need to publish this client so that other functions in this file will be able to use it
});



module.exports = {
    doSomething: function() {
        //how can I access the client here?
    }
};

How would I go about doing this?

Upvotes: 1

Views: 964

Answers (2)

Freyja
Freyja

Reputation: 40824

One solution to this problem is to use promises:

var soap = require('soap');
var url = 'http://someurl?wsdl';

var clientPromise = new Promise(function(resolve, reject) {
    soap.createClient(url, function(err, client) {
        if (err) {
            // reject the promise when an error occurs
            reject(err);
            return;
        }
  
        // resolve the promise with the client when it's ready
        resolve(client);
    });
});


module.exports = {
    doSomething: function() {
        // promise will wait asynchronously until client is ready
        // then call the .then() callback with the resolved value (client)
        return clientPromise.then(function(client) {
             // do something with client here
        }).catch(function(err) {
             // handle errors here
             console.error(err);
        });
    }
};

A few advantages to this:

  • Promises are native JavaScript objects (as of Node 4.0.0, with packages such as bluebird providing support for prior versions)
  • Promises can be "reused": if clientPromise has already resolved once, it will immediately resolve when doSomething is later called.

Some disadvantages:

  • doSomething and all other exported functions are inherently asynchronous.
  • Is not directly compatible with Node-type callbacks.

Upvotes: 2

JBone
JBone

Reputation: 1794

Not sure if my response helps you, but this is how I do. I create createClient every time and then within the client, I call the actual SOAP method (here GetAccumulators). May be not a great way, but this works for me. Here is my code sample

soap.createClient(url, function (err, client) {
  if (err) {
    logger.error(err, 'Error creating SOAP client for %s', tranId);
    reject('Could not create SOAP client'); 
  }

   client.addSoapHeader(headers);
  // envelope stuff
  client.wsdl.definitions.xmlns.soapenv = 'http://schemas.xmlsoap.org/soap/envelope/';
  client.wsdl.definitions.xmlns.acc = 'http://exampleurl/';
  client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap();

  client.GetAccumulators(args, function (err, result) {
    if (err) {
      if (isNotFoundError(err)) {
        logger.debug('Member not found for tranId %s', tranId);
        reject({status:404, description:'No match found'});
      }
      reject({status:500, description:'GetAccumulators error'});
    }
    return resolve({data: result, tranId: tranId});
  });

Upvotes: 0

Related Questions