Friday, May 20, 2011

Converting a WSDL to Javascript with Web 2.0 Feature Pack

In a previous post I discussed how easy it is to invoke web services from a browser using Websphere web 2.0 feature pack. One of the things I noticed is that it seems to parse the WSDL every time a page is loaded, which isn't necessary if we take a few additional steps.

Most developers who work with web services are familiar with a utility which converts a WSDL into generated code for a given language. Something like wsdl2java will generate java, wsdl2perl will generate perl and so on. What about wsdl2js?

As it turns out, the documentation for ibm_soap mentions that the parser holds JSON markup in a variable - all we have to do is grab the contents of that variable (smdString) and save it off to a file. Below is code that will parse a given WSDL and then copy the resulting JSON into a textbox for easy access.

<title>DsixE WSDL2JS</title>

<script type="text/javascript" src="dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true"></script>
<script type="text/javascript" src="ibm_soap/util/WsdlParser.js"></script>
<script type="text/javascript">
function wsdl2js() {
    // This is our homebrew wsdl2js. Json code is dumped to a textbox where
    // we can copy/paste it into a file.
    var wsdlParser = new ibm_soap.util.WsdlParser();
    var wsdl = dojo.byId("wsdl").value;
    dojo.byId("json").value = "var myService=" + wsdlParser.smdString;

    <H3>Generate JSON from WSDL (wsdl2js)</H3>
    WSDL must not contain externalized schema, all schema must be defined in the WSDL.
    WSDL URL: <input type="text" id="wsdl" size="80" value="http://"></input>
    JSON: <br><textarea id="json" rows="20" cols="80">var myService={}</textarea>
    <input type="button" id="callServiceButton" value="Create JS from WSDL" onclick="wsdl2js()"/>

I wish I could provide a working version on this blog, but I don't have access to a publicly available WAS server. Instead, here's a screenshot of what it looks like:

Now we can include our SOAP service using a script tag instead of parsing a WSDL every time a page loads.

Friday, May 13, 2011

Using Web Services from a Browser

For a long time I wondered why nobody has created a javascript library for web services. There are all kinds of libraries for REST services, but they're not very developer friendly. I much prefer the structure provided by a WSDL, and with tools like wsdl2java creating stubs for my code is a snap.

IBM's Dojo Soap Library

IBMS's Websphere application server offers a set of dojo extensions in their web 2.0 feature pack (FEP) which includes a SOAP library. I decided to take a look at it and found that it is quite easy to use although there aren't many examples to be found on the web. There is a sample provided with the feature pack but it uses the declarative dojo notation which doesn't work for everyone depending on what the goal is.

I opted to take a scripting approach since I already know how to invoke web services on the server side, and I wanted to see how it measures up in ease of use. Below is a simple example which retrieves data from a contacts web service I blogged about a while back.

Setting up the Infrastructure

My setup involved two different boxes - one running the webservice (axisbox) and another which hosted the HTML and the dojo SOAP library (dsixedev1). Due to the cross domain security restriction enforced by the browser, I also had to set up a reverse proxy (lenovobox). Your setup may vary, if everything runs on one box then this part doesn't really matter. Here's what I have in my apache httpd.conf:

ProxyPass /contacts http://lenovobox:8080/axis2
ProxyPassReverse /contacts http://lenovobox:8080/axis2

ProxyPass /was http://dsixedev1:9080
ProxyPassReverse /was http://dsixedev1:9080

The WSDL is loaded using this code:
var wsdlParser = new ibm_soap.util.WsdlParser();

Note that I don't load the WSDL directly from the service because it contains a reference to an external schema:
   <xsd:import namespace="" schemaLocation="ContactService.ContactInfoPort?xsd=ContactService_schema1.xsd"/>

This reference causes the parser to fail, so I have to manually copy/paste the schema into the WSDL and then save it on the WAS server.

Putting it all Together
Here's a complete listing of the HTML document:
<title>DsixE SOAP Sample</title>

<script type="text/javascript" src="dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true"></script>
<script type="text/javascript">
    function init() {
        var wsdlParser = new ibm_soap.util.WsdlParser();

        // Create reference to service and set the URL
        var myService = new ibm_soap.rpc.SoapService(wsdlParser.smdObj);
        myService.serviceUrl = "http://lenovobox/contacts/services/ContactService.ContactInfoPort/";

        var params = new"getContact");
        params.setPropertyValue("arg0", "ABC123");
        deferred = myService.getContact(params);
            // do something useful with the data here
            var phone = dojo.query("phone",xmlData)[0].textContent;
            var name = dojo.query("name",xmlData)[0].textContent;
            dojo.byId("contact").innerHTML = name + " " + phone;



<H3> DsixE SOAP Sample - Calling a custom Contacts web service </H3>

This is a pure javascript example of how to invoke a SOAP operation without using declarative dojo markup.

<div id="contact"/>


the SOAP response:
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="">
        <dlwmin:getContactResponse xmlns:dlwmin="">
                <phone>678 555-1212</phone>

and the output it produces:
DsixE SOAP Sample - Calling a custom Contacts web service
This is a pure javascript example of how to invoke a SOAP operation without using declarative dojo markup.

Carl 678 555-1212

Overall I'm really pleased with the way IBM has done this, I've always been leery of REST services because they lack a structured type definition available in a WSDL, and the SOAP approach makes the code much easier to read.