Working with SOAP in a Node App

This post is more than 2 years old.

I've been lucky to have been able to avoid SOAP for a few years now, but today there was an API I wanted to work with that had this right on top of their documentation:

The API is implemented as an XML SOAP web service. Please read the the WSDL. There are no plans at present to make it available via JSON.

My reaction was, of course, quite reasonable.

"Yes, I barfed"

So once I got over that initial reaction, I thought, "I wonder how folks in Node-land work with SOAP?" I did a bit of research and found a great solution, node-soap.

node-soap lets you easily make SOAP calls to web services as well as setup your own SOAP service if you need to. And let's be honest, that's the only reason you would set one up because, my god... SOAP. (Sorry, I promise not to rag on SOAP and WSDL anymore. Not a lot anyway.)

The API in question was one for the site, Brickset. Brickset is a nice little site that contains a huge amount of information on Lego brick sets. It's got a huge product directory as well as an events calendar and forum. I've built a few Lego sets in my life, but I'm thinking about getting a bit more involved next year so this looks to be a great resource.

"Brickset.com"

On top of that, they have an API! A SOAP API, but no one's perfect, right? I thought it might be fun to build a little app to randomly select a Lego set from their database. I've done "select a random X from the db" thing a few times now (see "Building a Twitter bot to display random comic book covers" as an example) and I don't know but the idea just interests me. I'll sit there and just reload and just... explore.

So with that in mind, I began writing. I create a simple web page that would make an Ajax call to my local Node server. I'd have a route that would handle finding the random set and then returning that JSON to the front-end code. I'm assuming most of the front-end code and route stuff isn't interesting, so I'll just share the module I wrote to work Brickset's API. It shows you how nice node-soap was to work with.

var soap = require('soap');
var apiWSDL = 'http://brickset.com/api/v2.asmx?WSDL';

var key = '';

//based on searching brickset.com
var minYear = 1950;

function getRandomInt (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function setKey(k) {
	key = k;
}

function getRandomSet() {

	//first, determine the year
	year = getRandomInt(minYear, (new Date()).getFullYear());
	console.log('chosen year', year);

	var p = new Promise(function(resolve, reject) {
		
		soap.createClient(apiWSDL, function(err, client) {
			if(err) throw new Error(err);

			var args = {
				apiKey:key,
				userHash:'',
				query:'',
				theme:'',
				subtheme:'',
				setNumber:'',
				year:year,
				owned:'',
				wanted:'',
				orderBy:'',
				pageSize:'2000',
				pageNumber:'1',
				userName:''
			}

			client.getSets(args, function(err, result) {
				if(err) reject(err);
				if(!result) {
					return getRandomSet();
				}

				var sets = result.getSetsResult.sets;
				console.log('i found '+sets.length+' results');
				if(sets.length) {
					var chosen = getRandomInt(0, sets.length-1);
					var set = sets[chosen];
					// now that we have a set, try to get more images
					if(set.additionalImageCount > 0) {
						client.getAdditionalImages({apiKey:key, setID:set.setID}, function(err, result) {
							if(err) reject(err);
							console.log('i got more images', result);
							set.additionalImages = result;
							resolve(set);
						});
					} else {
						resolve(set);
					}
				}
			});
		});
		
		
	});

	return p;

}

exports.setKey = setKey;
exports.getRandomSet = getRandomSet;

To handle selecting a random set, I used the following logic. First, I searched a bit on Brickset to determine what was the earliest year of data. While I found one year in the 40s with one result, 1950 was the first year to have multiple results. So selecting the year is simply a random selection between 1950 and the current year.

As far as I could tell, their API allowed you to select as many items as you want in your call, so I used a pageSize value of 2000 to grab everything. Then it was simply a matter of selecting a random set.

The SOAP client is created with soap.createClient, and note that all I have to do is pass in the WSDL. WSDL is the "descriptor" for SOAP services. Imagine asking someone to write up documentation for an API, then throw that away and select 20000 random words from the dictionary. That's WSDL.

Actually calling the API is done via client.X, where X is the specific method. In this case I just called getSets. I noticed that if I didn't pass every argument, the result was null. I don't know if that's a SOAP thing or a particular issue with the API, but that's why that args object has a bunch of empty values.

The API also supports returning additional images, so you can see I call that too, but I never ended up using it in the front end. Maybe next time.

And that's it. Here's a random example:

"Example"

And another:

"Example"

I don't know why, but I just love seeing those old sets. Anyway, you can give it a whirl yourself if you want, although I've been having some issues with Bluemix today so forgive me if it isn't up and running.

http://randombrickset.mybluemix.net/

And as I said, if you want to see the rest of the code, just let me know!

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Simon Prickett posted on 10/12/2016 at 10:13 PM

Nice - I'm sure we could write them a JSON wrapper for their API. I didn't like that SF BART only had XML so did that for theirs and made it available.

Comment 2 (In reply to #1) by Raymond Camden posted on 10/12/2016 at 10:16 PM

In theory I could have added routes for all of their routes and created exactly that. But I just built the bare minimum for my little demo. LoopBack allows you to do stuff like this and I talk about it here: https://strongloop.com/stro...

Although actually - that requires a REST API on the back end. You *could* use LoopBack to do this, but it would be a bit more grunt work.

Comment 3 by Radha posted on 12/21/2017 at 5:29 PM

Hi Raymond,
Is there a way we can auto-generate SOAP-XML request using wsdl file in the client code instead of json ?

Comment 4 (In reply to #3) by Raymond Camden posted on 12/21/2017 at 5:38 PM

Sorry - I only used the package enough to get me to the point where I could consume a service.

Comment 5 by Terence Watson posted on 8/7/2018 at 5:11 AM

does that args object include header elements? or is just the body elements?

Comment 6 (In reply to #5) by Raymond Camden posted on 8/7/2018 at 12:38 PM

I think it is just arguments to the method.

Comment 7 by Charly Iván Bernabe Bernabe posted on 8/9/2018 at 6:04 PM

I would like to know how to implement the whole function, in the part of the exports.getRandomSet ... I do not know how to implement it in the call of a route, for example .... router.post ('/ logtrans /: id /', (req, res) => {
var params = req.body; // phone
var data = req.params; // id_sucursal and the package
var datos_empresa = datos.id.split ("ffft");

here..... help me pleasee

Comment 8 (In reply to #7) by Raymond Camden posted on 8/9/2018 at 6:55 PM

Oops, had to delete my comment as I included the API key. ;) Anyway, here is the code for app.js for the demo:

var express = require('express');
var app = express();

var apiKey = 'put your key here';

var brick = require('./brick');
brick.setKey(apiKey);

app.set('port', process.env.PORT || 3000);
app.use(express.static('public'));

app.get('/random', function(req, res) {

brick.getRandomSet().then(function(set) {
console.log('set is '+JSON.stringify(set));
res.send(set);
});

});

app.listen(app.get('port'), function() {
console.log('Express running on http://localhost:' + app.get('port'));
});

Comment 9 by Mo Dev posted on 10/3/2018 at 7:37 AM

I tried using soap as well as strong-soap but i am getting html page with list of all methods as response.
Can you let me know what is wrong ?

Comment 10 (In reply to #9) by Raymond Camden posted on 10/3/2018 at 3:57 PM

Did you try adding ?wsdl to the URL?

Comment 11 (In reply to #10) by Mo Dev posted on 10/3/2018 at 4:26 PM

Yes, its the same as the example shared.
var apiWSDL = 'http://brickset.com/api/v2....

Comment 12 (In reply to #11) by Raymond Camden posted on 10/3/2018 at 4:54 PM

Sorry - you got me there. I haven't used this particular service in a while.

Comment 13 (In reply to #12) by Mo Dev posted on 10/6/2018 at 8:43 AM

Can u see if it works for u ? i have been struggling to get it to work.

Comment 14 (In reply to #13) by Raymond Camden posted on 10/23/2018 at 1:30 PM

Sorry - I'm completely booked (hence my delay in responding).

Comment 15 by Eagle posted on 4/15/2019 at 11:11 AM

throws Error: Error: connect ECONNREFUSED 104.25.205.7:80

Comment 16 (In reply to #15) by Raymond Camden posted on 4/15/2019 at 2:08 PM

It means it couldn't connect to the API. So either a network issue on your end (see if your corporate VPN blocks it) or the server is down.

Comment 17 by Lars Jeppesen posted on 10/22/2019 at 5:46 PM

You're extremely lucky it worked.. node-soap has many problems with WSDL and soap specifications with different namespaces etc..

Comment 18 (In reply to #17) by Raymond Camden posted on 10/22/2019 at 5:52 PM

And I've never used it again. Thank god.

Comment 19 by Samil Kahraman posted on 1/11/2020 at 5:27 AM

Hi, how did you handle the response coming from soap? Because when i parse the response to json, it contains lots of character that is not accepted by json like ":"

Comment 20 (In reply to #19) by Raymond Camden posted on 1/11/2020 at 7:12 PM

I honestly don't remember the shape of the response. Can you share a pastebin link showing the data you are trying to parse?

Comment 21 by Mohanaprabhu V posted on 1/23/2020 at 8:31 AM

Hi Raymond, I have Dot net soap service, Using node js code i need to post data to those methods. Cam you please send me sample code to post data to web service

Comment 22 (In reply to #21) by Raymond Camden posted on 1/23/2020 at 3:57 PM

No, I can't do that. I can try to answer questions, but I do not write sample code for folks.