Thursday, July 28, 2011

Using JSONP in Datapower

For one of our clients we needed to create multiple JSONP services with SOAP-backends in Datapower. JSON is supported by default in het Multi-Protocol gateway, and with JSONx, Datapower can handle it quite well. This post describes the fixes we did to extend JSONx and make it easy to create a JSONP-response in the same way you would do for a JSON-response.

For those of you who never heard of JSONP (JSON with Padding): it’s JSON wrapped in round brackets, preceded with a prefix. This makes it possible for javascript to use it as if it where a javascript function. It is used to allow a web page to request data from a server in a different domain (our datapower device).

Back to our case: the strenght of Datapower is its ability to handle XML content. Since JSON is no xml, IBM provided us with a language called JSONx. It is an XML-model that represents JSON-content. The idea is to work as long as possible with JSONx and after all mappings and validations are done the conversion to a proper JSON response can be done using the provided ‘jsonx2json.xsl’ style sheet. This stylesheet is by default available in the ‘store://’ directory on the Datapower appliance.

Since we wanted to use JSONP instead of JSON, we complemented the JSONX-language with an extra element <jsonp:callback> that will serve as a root for the normal JSONX content. The new name we used for it is JSONPx. It has one property: ‘name’. The value of this property will be used as the prefix for our JSONP-response. If ‘name’ is empty, the output will be normal JSON.
Here you can see of a sample of a JSONPx-file:
<jsonp:callback
  xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
  xmlns:jsonp="http://www.i8c.be/xmlns/jsonpx" name="TestPrefix">
  <json:object>
     <json:number name="testValue">123</json:number>
     <json:string name="testName">Foo</json:string>
  </json:object>
</jsonp:callback>

Just like for a JSONx-file it is possible to validate this file against an XSD-schema. Instead of the default jsonx.xsd (located under ‘store://‘in Datapower), you now can use the XSD below and we called it jsonpx.xsd;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:tns="http://www.i8c.be/xmlns/jsonpx"
  targetNamespace="http://www.i8c.be/xmlns/jsonpx" 
  elementFormDefault="qualified"   attributeFormDefault="unqualified">
<xs:import namespace="http://www.ibm.com/xmlns/prod/2009/jsonx"
           schemaLocation="store:///jsonx.xsd"/>
<xs:element name="callback" type="tns:callback"/>                       
   <xs:complexType name="callback">          
      <xs:sequence>
         <xs:any namespace="http://www.ibm.com/xmlns/prod/2009/jsonx"
            minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attribute name="name" type="xs:string"/>        
   </xs:complexType>
</xs:schema>

For the transformation we use the XSLT called ‘jsonpx2json.xsl’ which imports the transformations from the ‘jsonx2json.xsl’ file, but adds the transformation for the jsonp:calback element to it.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     version="1.0" 
     xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" 
     xmlns:jsonp="http://www.i8c.be/xmlns/jsonpx">
<xsl:output method="text" encoding="utf-8" 
  indent="no" media-type="application/javascript"/>          
  <xsl:import href="store:///jsonx2json.xsl"/>
  <xsl:template match="jsonp:callback">
     <xsl:if test="string-length(@name)>0">
        <xsl:value-of select="@name"/>
        <xsl:text>(</xsl:text>      
     </xsl:if>
     <xsl:apply-templates select="*"/>
     <xsl:if test="string-length(@name)>0">
        <xsl:text>)</xsl:text>
     </xsl:if>
  </xsl:template>
</xsl:stylesheet>



Author: Tim

No comments:

Post a Comment