An Express service for parallel SOAP invocation in under 25 lines of code

Felipe Lazo
Aug 9, 2018 · 6 min read
Most lines are not parallel, but you get the idea. Image credit: Internet Archive Book Images


Let’s suppose there is a service that has the following features:

  1. It exposes a REST endpoint receiving a list of requests.
  2. It in parallel invokes a SOAP service, once per element in the requests list.
  3. It returns the converted result from XML to JSON.

That service’s source code could look something like this using Node.js, Express, and the Airbnb JavaScript Style Guide:

Just as I promised, 24 lines of code.

Sample request:

Sample response:

Tests show that a single direct request to the SOAP service using SOAPUI takes ~430 ms (from where I’m located, in Chile). Sending three requests (as shown above) takes ~400 ms for calls to the Express service (other than the first one, which gets the WSDL and builds the client).

Why do more requests take less time? Mostly because the XML is not heavily validated as it is in regular SOAP, so if this soft validation doesn’t match your expectations, you should consider additional features or solutions.

Wondering how would it look using async/await? Here you go (results are the same):

The following image provides a concept of how the code works:

This article aims to show the simplicity of using JavaScript for tasks in enterprise World, such as invoking SOAP services. If you’re familiar with JavaScript, this is basically just a Promise.all on top of a couple of promisified callbacks under an Express endpoint. You can go directly to section 4 (Bonus track) if you think that could be useful for you.

If you’re outside the JavaScript world, I think that 24 lines of code for the three features I mentioned at the beginning are a very good deal. I’ll now go into the details.

1. The Express section

Let’s start with the code related to Express, a minimal and flexible Node.js web application framework. It’s quite simple and you can find it anywhere, so I’ll give a summarized description.


Now we’ll need to handle an object sent through POST. Express body-parser allows easy access to the body of the request:

So, long story short: setup the Express app, and as soon as you have the result, send it via res and voilà.

2. The SOAP section

This will have some more steps than the previous section. The main idea is that, for making SOAP invocations in parallel, I’ll use Promise.all. In able to use Promise.all, the invocation to the SOAP services needs to be handled within a Promise, which is not the case for strong-soap. This section will show how to convert the regular callbacks from strong-soap into Promises and then putting a Promise.all on top of that.

The following code will use the most basic example from strong-soap’s documentation. I’ll just simplify it a bit and use the same WSDL we’ve been seeing (I didn’t use the same WSDL stated in strong-soap’s documentation, since that WSDL is not working anymore):

I’ll convert this into Promises and I’ll go through all callbacks, one by one, for the sake of the example. That way the translation process will be crystal clear for you:

Calling node index.jsgets the same result as before. Next callback:

node index.js? Still the same. Let’s wrap those Promises in a function, in order to prepare the code for calling it inside the Express endpoint. It also simplifies the error handling a bit:

I bet you can guess the result of node index.js.

What happens if several subsequent calls are made? We’ll find out with the following code:

Not good, as several clients are being created. Ideally, the client should be cached and reused. There are two main ways to achieve this:

  1. You can create a variable outside the Promise and cache the client as soon as you have it (just before resolving it). Let’s call this cachedClient. But, in that case, you’d have to manually deal with calls to createClient() made between the first time it is called and before the first client is resolved. You’d have to inspect if cachedClient is the expected value, or you’d have to check if the Promise is resolved or not, or you’d have to put some kind of event emitter to know when the cachedClient is ready. The first time I wrote code for this, I used this approach and I ended up living with the fact that every single call made before the first createClient().resolve overwrote cachedClient. If the problem is not that clear, let me know and I’ll write the code and the examples.
  2. Promises have a very cool feature (see MDN documentation, “Return value” section): if you call .then() on a resolved/rejected Promise, it will return the very same value that was resolved/rejected, without processing again. In fact, very technically, it will be the very same object reference.

The second approach is much simpler to implement, so the related code is the following:

Finally for this section, let’s make the code handle several parallel calls. This will be easy:

  1. For handling several parallel calls, we’ll need Promise.all.
  2. Promise.all has a single parameter: an array of Promises. So we’ll be converting the list of requests into a list of Promises. The code currently converts a single request into a single Promise (invokeOperation), so the code just needs a .map to achieve this.

3. Putting it all together

This is fairly easy — it’s just assembling the last code from each previous section:

Hmmm… Not a good result, since I did not expect an error at all. The problem is that invokeOperations doesn’t have req in its scope. The first thought could be “Just add it to the signature.” But that’s not possible, as that signature matches the result from the previous Promise, and that promise doesn’t return req, it only returns client. But, what if we add an intermediate Promise whose only purpose is injecting this value?

This can also be achieved via currying.

The results are exactly the same as the ones at the summary.

4. Bonus track

A generic SOAP to JSON converter for parallel SOAP invoking. The code is familiar, based on what you saw in the former sections. How about that?

First use example:

Second use example:

Are you going through Digital Decoupling? In a JavaScript full-stack architecture on top of the old services, this artifact could help you encapsulate all SOAP services, extend them, and expose only JSON. You could even modify this code a bit to call several different SOAP services at the same time (that should be just an additional .map and .reduce, as I see it right now). Or you could encapsulate your enterprise’s WSDLs in a database and invoke them based on a code or some identifier. That would be just one or two additional promises to the chain.

This is no longer updated. Go to instead

Felipe Lazo

Written by

Developer at ZeroFOX Chile

This is no longer updated. Go to instead

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade