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.
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.
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:
And another:
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!
Archived Comments
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.
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.
Hi Raymond,
Is there a way we can auto-generate SOAP-XML request using wsdl file in the client code instead of json ?
Sorry - I only used the package enough to get me to the point where I could consume a service.
does that args object include header elements? or is just the body elements?
I think it is just arguments to the method.
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
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'));
});
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 ?
Did you try adding ?wsdl to the URL?
Yes, its the same as the example shared.
var apiWSDL = 'http://brickset.com/api/v2....
Sorry - you got me there. I haven't used this particular service in a while.
Can u see if it works for u ? i have been struggling to get it to work.
Sorry - I'm completely booked (hence my delay in responding).
throws Error: Error: connect ECONNREFUSED 104.25.205.7:80
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.
You're extremely lucky it worked.. node-soap has many problems with WSDL and soap specifications with different namespaces etc..
And I've never used it again. Thank god.
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 ":"
I honestly don't remember the shape of the response. Can you share a pastebin link showing the data you are trying to parse?
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
No, I can't do that. I can try to answer questions, but I do not write sample code for folks.