2

I'm trying to make a function that returns the results of a SOAP call (using npm-soap in combination with node.js). The problem is that the function returns undefined because the SOAP call isn't finished yet when the return statement is reached.

I tried putting the return statement in the SOAP call callback itself, but then it returns undefined. I think this is because the return statement should be in the outer function instead of the inner function, just like I did in the example below. A console.log() in the SOAP call callback outputs the right data, so I know it's there.

How do I make the return statement wait on the inner SOAP call? Thanks!

var config = require('./config.js');
var soap = require('soap');

function getInvoices() {

    let invoices;

    // Connect to M1
    soap.createClient(config.endpoint, function(err, client) {

        // Log in
        client.login(
            { 
                username: config.username,
                apiKey: config.password
            }, 
            function(err, loginResult) {

            // Get invoices
            client.salesOrderInvoiceList(
                { 
                    sessionId: loginResult.loginReturn.$value
                }, 
                function(err, invoiceResult) {

                    // Save invoices
                    invoices = invoiceResult;
                    console.log(invoices); // <- Returns the right data

                    // Log out
                    client.endSession(
                        { 
                            sessionId: loginResult.loginReturn.$value
                        },
                        function(err, logoutResult) {
                        }
                    );

                }
            );

        });

    });

    // Return invoices
    return invoices; // <- Returns undefined

}

console.log(getInvoices(); // <- So this returns undefined as well
Jonathan
  • 21
  • 1
  • 2
    Welcome! The best way, is not to wait at all, but instead specify what needs to happen once those invoices get there. And in a way, that's what you have. The inner function is where you get the invoice, and that's also where you can specify what to do with them. If you want to wrap all the soap stuff, you can pass a callback to the getInvoices function, and call that callback as soon as your get the invoices from the SOAP client. – GolezTrol Jan 30 '20 at 23:05
  • 2
    Does this answer your question? [How to make a function wait until a callback has been called using node.js](https://stackoverflow.com/questions/5010288/how-to-make-a-function-wait-until-a-callback-has-been-called-using-node-js) – GolezTrol Jan 30 '20 at 23:06
  • 1
    @GolezTrol Actually, your first reply answered my question. It's my first Node.js/Javascript app ever that I'm building and I've been struggling with this problem for hours. But rethinking the overall structure instead of applying complex fixes sounds like a good way to go. I've restructured my files and code and it now works like you suggested. I'm actually even more happy with the final result because it's more logical and easier to follow. I'll make this my new mindset from now on :) Thank you! – Jonathan Jan 31 '20 at 07:45

1 Answers1

1

Have getInvoices return a Promise which you can then resolve once all the callbacks finish i.e.

function getInvoices() {
  return new Promise((resolve, reject) => {
    // Connect to M1
    soap.createClient(config.endpoint, (err, client) => {
      if (err) return reject(err);

      // Log in
      client.login({ 
        username: config.username,
        apiKey: config.password
      }, (err, loginResult) => {
        if (err) return reject(err);

        // Get invoices
        client.salesOrderInvoiceList({ 
          sessionId: loginResult.loginReturn.$value
        }, (err, invoiceResult) => {
           if (err) return reject(err);

           // Log out & resolve the Promise
           client.endSession({ 
             sessionId: loginResult.loginReturn.$value
           }, (err, logoutResult) => 
             err ? reject(err) : resolve(invoiceResult)
           );
        });
    });
  });
}
...
(async () => {
  try {
    const invoices = await getInvoices();
    console.log(invoices);
  } catch (e) {
    console.error(e);
  }
})();
James
  • 80,725
  • 18
  • 167
  • 237