How to perform SOAP Requests with Node.js

What is SOAP?

SOAP stands for Simple Object Access Protocol. It’s basically the only thing that existed before REST. It’s an XML based API…before going any further, know that REST is much, MUCH better.

A SOAP server consists of something called a WSDL(Web Services Description Language) which contains an XML schema to define what actions can be sent to the server. Think of REST API docs.

How to consume a SOAP service?

After about an hour or two of browsing the web for a SOAP service that still worked, I found one. Luckily NOAA still has some functioning legacy tech which uses SOAP.

To hit a SOAP API, you need to send a POST request containing a few things:

  • The right headers(usually two)
  • A SOAP envelope

Headers

For almost all SOAP requests, you need to send the data in XML format, so you’ll need:

Content-Type: text/xml;charset=UTF-8

Another header you will need to send will be the “soapAction”. Now not all services require a soapAction(if the WSDL says soapAction=””), but if the SOAP service provides multiple functions, you’ll usually need to send it. The way you find the soapAction will be to “ctrl+f” the WSDL or rely on API docs if they exist, which are hard to find in my opinion since SOAP is pretty dated. Here’s the WSDL I’ll be testing provided by NOAA.

Here’s an example soapAction for the above mentioned WSDL:

soapAction:'https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl#LatLonListZipCode'

To conclude, we will at minimum need those two headers, but you may also want to add a third to be friendly to some external web services that require a user-agent for example:

user-agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19"

SOAP Envelope

Next you’ll need to send a SOAP “payload” to the service. This is the data you want the service to use before getting your response back. Most developers I’ve worked with use a tool called SOAP UI to generate their payloads.

When you input a WSDL(local file or http URL) in SOAP UI, it will generate “SOAP Bindings” and test cases(for all the soapActions) in the sidebar tree. These are boilerplate XML schemas for your SOAP web service to consume. All you do is fill in the data.

For the NOAA service, I plugged in this WSDL and I checked the “create Test Suite for SOAP bindings” option and all the test cases were rendered for me. I just had to replace the “?” in the envelope with acceptable data to consume the service.

Video on using SOAP UI

Testing the service with curl

I wanted to test the service with something pretty minimal and raw to ensure SOAP UI wasn’t waving magic in front of me and so I can fully understand what was happening behind the scenes.

I copied the envelope for the LatLonListZipCode soapAction out of SOAP UI and pasted it into a file for curl to use(passing in as string would’ve made for a long command).

I then replaced the “?” in between the <zipCodeList> tag with a valid ZIP code and ran the following command:

Low and behold I got the following response and gave me the correct latitude and longitude coordinate data!

Why would I use Node.js to consume something so old like SOAP?

If you’re like me and work at a large company, you’ll know that legacy tech gets propelled and maintained for far too long. I’m more partial to use modern tools like Node to get the job done because I can write less code, faster.

I was tasked with writing integration tests for old SOAP services in java… I despise java. There is simply too much code to write something simple like an HTTP request. I thought… I bet I can do this easily in Node.

The easy-soap-request node module

There were several popular SOAP node js modules to choose from to perform SOAP requests with such as

But I managed to find something wrong with all of them for my use case. It was either too much code or too much overhead. I thought to myself, “I just need to send 3 parameters, that’s it. Why such an extensive docs for all the modules when I want to do something so simple”. So…

I wrote a simple .js file to recreate the procedure above using the request module just performing a POST request, but thought “This is still too much code to do something this simple…”. So I created the easy-soap-request node module.

There’s not much to the module, but it provides “lift”. It will save time for those who are just learning about the dreaded legacy SOAP. Here’s what the module looks like:

The module takes 3 parameters(url, headers, xml) with xml being the soap envelope.

It uses the newer async await syntax so you can get all fancy-smancy with your asynchronous coding and what not.

Actually using the thing

First, you’ll need to install the module by running:

npm install easy-soap-request

Next you need to create a .js file and require the module like on line 1 below.

Here’s a good example:

On line 11, I read in the XML from a file because that would be an exhaustingly long string, but the preference is yours.

On line 15, you can see where I’ve created a “destructured” object by waiting for the soapRequest function to return both the body of the response and the status code.

Here is where you can find the repo with README and the module on npm.

Testing with mocha and chai

Here’s how you can perform the same above, but inside a testing framework:

Fin

Thanks for reading and hopefully you can move on to REST in the near future!