Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Ws.js: A Ws-* implementation for Node.js

5.00/5 (1 vote)
25 Apr 2012CPOL3 min read 36.4K  
Ws.js is a Node.js module that allows to consume soap web services which utilize ws-* standards (ws-security, mtom etc)

Introduction 

Node.js is great platform for writing scalable server applications. Some of these applications would need to communicate with existing web services. As long as these services are Rest based this will not be a problem - Rest services are first class citizens in node. If we need to consume a soap web service, we could do a short googling to find node-soap or alternatively we can decide to handcraft the soap envelope ourselves. The real challenge is when node needs to consume soap services that utilize WS-* standards (WS-Security, MTOM etc). When I faced this situation a few months ago I could not find any module to help. This is why I decided to build Ws.js

Using the Code 

1. First you must  install the Ws.js module: 

npm install ws.js   

2. Now write your code: 

JavaScript
var ws = require('ws.js')
  , Http = ws.Http
  , Security = ws.Security
  , UsernameToken = ws.UsernameToken

var request =  '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">' +
                  '<Header />' +
                    '<Body>' +
                      '<EchoString xmlns="http://tempuri.org/">' +
                        '<s>123</s>' +
                      '</EchoString>' +
                    '</Body>' +
                '</Envelope>'

var ctx =  { request: request 
           , url: "http://service/security"
           , action: "http://tempuri.org/EchoString"
           , contentType: "text/xml" 
           }

var handlers =  [ new Security({}, [new UsernameToken({username: "yaron", password: "1234"})])
                , new Http()
                ]

ws.send(handlers, ctx, function(ctx) {                    
  console.log("response: " + ctx.response);
})  

Let's analyze this sample.  This following code imports the relevant modules: 

JavaScript
var ws = require('ws.js')
  , Http = ws.Http
  , Security = ws.Security
  , UsernameToken = ws.UsernameToken 

The next lines define the soap envelope and some required information such as the url. Note that we need to build the soap out of band - Ws.js is not a soap engine. However this is usually easy as we typically have a working soap sample. 

JavaScript
var request =  '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">' +
                  '<Header />' +
                    '<Body>' +
                      '<EchoString xmlns="http://tempuri.org/">' +
                        '<s>123</s>' +
                      '</EchoString>' +
                    '</Body>' +
                '</Envelope>'

var ctx =  { request: request 
           , url: "http://service/security"
           , action: "http://tempuri.org/EchoString"
           , contentType: "text/xml" 
           } 

The next lines are the heart of the ws-* usage. We define the protocols we want to use in the request. This specific request uses the ws-security standard and configures it to send a username token.

JavaScript
var handlers =  [ new Security({}, [new UsernameToken({username: "yaron", password: "1234"})])
                , new Http()
                ]   

Finally, this piece of code sends the request (using the specified protocols) and handles the response.  

JavaScript
ws.send(handlers, ctx, function(ctx) {                    
  console.log("response: " + ctx.response);
})    

The resulting soap looks like this:  

JavaScript
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<Header>
  <o:Security>
    <u:Timestamp>
      <u:Created>2012-02-26T11:03:40Z</u:Created>
      <u:Expires>2012-02-26T11:08:40Z</u:Expires>
    </u:Timestamp>
    <o:UsernameToken>
      <o:Username>yaron</o:Username>
      <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">1234</o:Password>
    </o:UsernameToken>
  </o:Security> 
</Header>
<Body>
  <EchoString xmlns="http://tempuri.org/">
    <s>123</s>
  </EchoString>
</Body>      

MTOM Sample 

Sending MTOM attachments is pretty similar. We just need to specify the file we want to send and the path to the soap element it corresponds to: 

//add attachment to the soap request
ws.addAttachment(ctx, "request", "//*[local-name(.)='File1']", 
                "me.jpg", "image/jpeg")
var handlers =  [ new Mtom()
                , new Http()
                ];   

The full sample is here

Supported Protocols 

Currently Ws.js supports the following protocols:  

  • MTOM   
  • WS-Security (username token only) 
  • WS-Addressing (all versions)
  • HTTP(S)    

Behind the Scenes 

Ws.js uses the chain of responsibility design pattern to call the different protocols. This is an extensible patterns so anyone can add new protocol implementations. While this is a known pattern for soap stacks, implementing it in javascript can be a little tricky. The key is for each handler to have a send() and a receive() methods. Sending actually passes the control to the next handler. We give that handler a callback method. That callback will call our receive() passing it the context and the original callback we got (which the downstream handler has no idea about). It is best to see the code: 

JavaScript
SecurityHandler.prototype.send = function(ctx, callback) {
  var self = this

  //actual logic here...

  this.next.send(ctx, function(ctx) { 
    self.receive(ctx, callback)
  })
}

SecurityHandler.prototype.receive = function(ctx, callback) {

  //optionally post processing here...

  callback(ctx)
}

var s = new SecurityHandler()
s.next = new HttpHandler()
s.send(ctx, function(ctx) {...})  
   

Like many node app, Ws.js also uses some external modules. It especially relies on strong xml processing libraries. As I note here, it was not trivial to find dom based node.js xml parser which works on windows. I finally found xmldom and xpath.js.  

Other notable libraries used by Ws.js are node-formidable and node-bufferjs which are helpful in the context of mime parsing.  

The future of Ws.js   

Ws.js is a growing framework. For future versions I plan to add more advanced security standards like X.509 digital signature and encryption. If you have any special request send me an email from my blog. If you want to help feel free to fork Ws.js on github - that's the fastest way to grow Ws.js. 

More Information  

Check out the project github page 

Check out my blog 

Check out my twitter 

Drop me an email from my blog 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)