Tuesday, April 8, 2014

How to parse Complex data types or arrays through payload in a synapse template of a connector for WSO2 ESB?

Here I am going to focus on a REST API where we should be able to pass objects or arrays as a rest request in json. Let me start with a real word example as shown below.

API:                     Google Calendar
Function:             CalendarList: insert
Reference Link: https://developers.google.com/google-apps/calendar/v3/reference/calendarList/insert
Sample REST Request:

{
    "id": "836g6ropqm741sqsjl7abcde@group.calendar.google.com",
    "defaultReminders": [
        {
            "method": "email",
            "minutes": 60
        }
    ],
    "notificationSettings": {
        "notifications": [
            {
                "type": "eventCreation",
                "method": "email"
            },
            {
                "type": "eventResponse",
                "method": "email"
            }
        ]
    }
}

Note that the above highlighted values are complex types such as defaultReminders being a list and notificationSettings being an object. The proxy will accept only the first level parameters. So that the objects and arrays will be accepted in the proxy as one single parameter as shown below.

<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="googlecalendar_createCalendarEntry"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence>        
         <property name="id" expression="json-eval($.id)"/>       
         <property name="defaultReminders" expression="json-eval($.defaultReminders)"/>
         <property name="notificationSettings" expression="json-eval($.notificationSettings)"/>         
         <googlecalendar.createCalendarEntry>
            <id>{$ctx:id}</id>         
            <defaultReminders>{$ctx:defaultReminders}</defaultReminders>           
            <notificationSettings>{$ctx:notificationSettings}</notificationSettings>           
         </googlecalendar.createCalendarEntry>
         <respond/>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </target>
   <description/>
</proxy>
              
Now the challenge comes on how we are going to add them to the payload factory inside the synapse template. Of course we have to use a script mediator because the above highlighted parameters are considered as optional parameters according to the API. Unlike handling string values, integers or even booleans, a valid json string does not accept "" surrounded within the values of complex types like arrays and objects but they should be sent within {} or []. 

To achieve the task, we must use eval function in JavaScript.

The eval() function evaluates or executes an argument.If the argument is an expression, eval() evaluates the expression. If the argument is one or more JavaScript statements, eval() executes the statements.
.
Note how it should be handled within a script mediator as shown below.

<script language="js">
        <![CDATA[      
               var defaultReminders = mc.getProperty('uri.var.defaultReminders');   
               var notificationSettings = mc.getProperty('uri.var.notificationSettings');
                            
var payload = mc.getPayloadJSON();
if ( defaultReminders != null && defaultReminders != "") { 
                 // if not null, add optional defaultReminders Array 
payload.defaultReminders = eval("("+defaultReminders+")");
}
if (notificationSettings != null  && notificationSettings != "") { 
                 // if not null , add optional notificationSettings JSON Obj
payload.notificationSettings = eval("("+notificationSettings+")");
}
mc.setPayloadJSON(payload);
]]>
</script>

Hope it was useful to you...