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();
wsdlParser.parse("contacts.wsdl");

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

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:
<html>
<head>
<title>DsixE SOAP Sample</title>

<script type="text/javascript" src="dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true"></script>
<script type="text/javascript">
  
    dojo.require("ibm_soap.widget.SoapService");
    dojo.require("dojox.wire.ml.util");
 
    function init() {
  
        var wsdlParser = new ibm_soap.util.WsdlParser();
        wsdlParser.parse("contacts.wsdl");

        // 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 dojox.wire.ml.XmlElement("getContact");
        params.setPropertyValue("arg0", "ABC123");
        deferred = myService.getContact(params);
  
        deferred.addCallback(function(xmlData){
            // do something useful with the data here
            console.log(xmlData);
      
            var phone = dojo.query("phone",xmlData)[0].textContent;
            var name = dojo.query("name",xmlData)[0].textContent;
      
            dojo.byId("contact").innerHTML = name + " " + phone;
      
        });
    }

dojo.addOnLoad(init);

</script>
</head>
<body>


<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.
<br><br>

<div id="contact"/>

</body>
</html> 

the SOAP response:
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <dlwmin:getContactResponse xmlns:dlwmin="http://dsixe.com/blog">
            <return>
                <name>Carl</name>
                <phone>678 555-1212</phone>
            </return>
        </dlwmin:getContactResponse>
    </soapenv:Body>
</soapenv:Envelope>

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.
Please note that generic comments containing links with the intent of self promotion will be flagged as spam and deleted.

1 comments:

  1. After spending alot of time on trying to get this to work, I finally did. It appears that that the wsdl schema needs to be inline in the wsdl. If the schema is referenced externally through the wsdl, then the wsdlParser.smdObj remains null. Once the schema is moved inline in the wsdl, all works well. This seems to be a great method to use and fairly simple to implement.

    ReplyDelete

Are you about to post a generic comment that has nothing to do with this post? Something like "Hey thanks for this very valuable information, BTW here's my website". If so, it will be marked as spam and deleted within 24 hours.

Note: Only a member of this blog may post a comment.