Home » Company » Sample applications » Example: VDF Ajax JSONP Interface

Example: VDF Ajax JSONP Interface

VDF Ajax JSONP – VDF, Ajax and JSONP sample application using JavaScript, JSON, JSONP and Ajax | Unicorn InterGlobal

Following on from our VDF Ajax JSON Interface sample, we thought we would do the same thing using JSONP rather than JSON over the conventional XMLHttpRequest from the web browser.

Doing this with VDF presents a number of technical challenges even on top of those we encountered with the JSON interface.

As our starting point, we looked at the steps that would be required to do this:

  1. We would need to modify the outgoing data (to apply the “P” aspect of JSONP), so all of the interface’s operations, rather than just a sub-set, would have to be “wrapped” by other methods.
  2. We would not be able to utilise VDF’s capability of returning JSON data, because that encoding takes place after the data leaves the programmer’s control when the complex data is returned from a published function, while it was that JSON data we needed to “wrap” in JSONP style, so we would have to do that encoding ourselves.
  3. In addition, we would not even be able to call the VDF operations directly as a web service, because if called “normally” they would wrap the returned string in an XML element as “<string>… our response …</string>”, while if called via the “/JSON” route, they would return a literal JSON string wrapped in double-quotes, rather than the raw JavaScript we needed to be delivered into our dynamic “<script>” tag.  We would have to involve an ASP script on the server to call the methods in the old, pre-web-services fashion (distasteful, but in this case necessary).


We determined that, for simplicity, each operation should only take a single JSON input parameter, since that JSON object could contain as much or as little complexity as was required, as well as returning a single JSON result.

Since we would be accessing the VDF functionality through an ASP script, what was required in the web application was an additional web object, rather than the additional web service we used in the JSON example.  The publshed methods of that object would be responsible for extracting the required arguments from the passed JSON and passing them on to the appropriate functions within the VDF Ajax interface.

Since the ASP script would be the common point that all of the calls would pass through, we decided that there was the appropriate place to apply the “padding” aspect of JSONP – the wrapping of the returned data in a JavaScript function call.

So let us start by looking at the ASP script which would be providing the actual web service end-point.

The ASP Script

The ASP script itself is trivially simple:

   Dim meth, json, func
   meth = Request("meth")
   func = Request("func")
   json = Request("json")
   If (json = "") Then
      Response.write func & "(" & oJsonP.call("get_" & meth) & ");"
      Response.write func & "(" & oJsonP.call("get_" & meth, json) & ");"
   End If

As you can see, it simply defines three variables (“meth” – the interface method to call, “func” – the JavaScript function to call with the returned data and “json” – the JSON string/object containing the inputs to the method), which it populates from the “Request” collection.  (This is really a super-collection and a more precise collection to access would be “Request.QueryString”, but in this case it is the simplest thing to use… and we like simple!)

If the “json” variable is empty, then it makes the call to the “oJsonP” object (our web object in the VDF web application in effect) in the form “get_meth“, otherwise it does the same thing, but also passing the “json” parameter.

Around this it wraps func “(”  …  “);”, returning the whole via “Response.write”.

And that is all there is to it!

The web object

The web object is just added into the web application without any complication:

Object oWebApp is a cWebApp
   Use SessionManager.wo
   Use WebService.wo
   Use Customer.wo
   Use Order.wo
   Use Invt.wo
   Use Salesperson.wo
   Use CustomerReport.wo
   Use OrderDtlReport.wo
   Use OrderReport.wo
   Use Vendor.wo
   Use CustomerTree.wo

   Use JsonP.wo  // Our new web object
End_Object  // oWebApp

Sture Andersen’s “SomeDegreeOfIntrospection” package (but read the “Health Warning” associated with it!) is also added to the top of the program source, just after the two standard “Use” statements.

Within the web object itself, we once again have an instance of John Tuohy’s JSON Parser, but in addition we also need a JSON Writer.  This turned out to be very simple to write: knowing (from Sture’s Introspection mechanism) what the members of complex data types (structs) were named and what data-type they were, made this just a matter of a hundred lines of VDF code in six functions: one to handle “objects” (structs), another to handle arrays, one to output values (calling one of the first two if the type of the member is itself complex or an array), one to encode strings (with escaped characters according to the JSON scheme), one to structure dates and a final one to map VDF data types to JSON data types.

Where in the JSON example we had made use of the command “ValueTreeDeserializeParameter”, renamed for understandability as “MoveValueTreeToStruct”, here we had to also use its conterpart “ValueTreeSerializeParameter”, renamed to “MoveStructToValueTree”, in order to move the returned struct variables into Value Tree variables which we could then translate into JSON.

Then it was just a matter of writing the interface functions themselves. Here is an example of one:

{ Published = True  }
{ Description = "JSONP form of VDF Ajax ’MetaDataWO’ operation"  }
Function MetaDataWO String JSON Returns String
   TAjaxMetaDataWORequest  req
   TAjaxMetaWO resp
   tValueTree Values Result
   Integer iStructNo iRespStruct
   Boolean bOK
   String sResp

   // Get the data-type indices:
   StructNum TAjaxMetaDataWORequest to iStructNo
   StructNum TAjaxMetaWO            to iRespStruct

   // This will deliver a Value-Tree with the JSON data:
   Get ParseJSONString of oReader (&JSON) (&Values) iStructNo to bOK

   If bOK Begin
      // Move the ValueTree to the struct variable:
      MoveValueTreeToStruct Values to req

      // Forward the request to the original web service:
      Move (MetaDataWO(oWebService(Self), ;
         req.sSessionKey, req.sWebObject, req.sVersion)) to resp
   // Move the returned struct data into a value tree:
   MoveStructToValueTree resp to Result

   // Serialise the resulting value tree into JSON:
   Get ObjToJson of oWriter Result iRespStruct to sResp

   // Return the JSON string:
   Function_Return sResp
End_Function  // Request

Nine such functions – one for each of the Ajax web service’s eight operations, plus one to create a session – and the server-side job was done.

The JavaScript Client

The HTML for this sample is pretty much identical to that of the JSON sample, except in using a different JavaScript file – “VdfAjaxJsonPInterface.js” – as its main program.

Within that JavaScript code, much of the structure is the same as the previous example, but rather than being invisibly hidden inside a function expression, the returned value from that expression – a JavaScript object – is assigned to a property of our “UIG” namespace object: “UIG.JsonP” in fact. This object exposes methods which in turn make calls to their “private” counterparts within the “closure“.  This is necessary in order to give the returned function calls from the JSONP dynamic script elements something to “hook onto”, so the “func” parameter passed into the back-end ASP script might be “UIG.JsonP.dispMetaWO” for instance. This will cause the method “dispMetaWO” of the interface object (“UIG.JsonP”) to be invoked and passed the returned JSON (now effectively JavaScript) data.  That interface method will then call its private counterpart within the closure, hopefully producing the required results.

The Set-Up

In order to demonstrate the worth of the JSONP technique over that of the XMLHttpRequest, we need to have two different servers involved, so while the page itself, and its JavaScript code, come from Unicorn’s public webacssite (www.UnicornInterGlobal.com, which resides in a hosting facility), the service it is calling – and the data that delivers – is sited on a server in our office which has VDF 16.1 installed on it, together with its sample applications, the Ajax Order Entry sample of which we have modified to produce our JSONP data server.

A Picture May Help

What is going on

Looking at the page in Firefox, with the Firebug debugger running, with its “Net” tab open will show what is going on:

Here we can see on the highlighted request that the HTML page – VdfAjaxJSONPInterface.html – has been loaded from www.unicorninterglobal.com.

While here we can see the JSONP request – in this case to the MetaDataWO operation – being made to the IP address (which reaches a server in our office).  We can also see that the file JSONP.asp is being requested and that it is being passed three parameters – meth, func and json – which can be seen more clearly in the “Params” tab at the bottom.

In this final frame, we have switched to the “Response” tab and can see the returned data as it comes back from the server.  It is a JavaScript function call to UIG.JsonP.dispMetaWO, which is being passed a JavaScript object literal: {“sname”: “oOrder”, “sdateformat”: “dd/mm/yyyy”… etc.

One small problem

If your eyesight is good (or your screen-resolution-to-monitor-size ratio is considerably smaller than mine!) you may have noticed something about the returned data: the property names are all in lowercase.  Instead of the camel-case “sDateFormat” we have the lowercase “sdateformat” and so on.

This is a result of the fact that Visual DataFlex is case insensitive.  When the compiler generates its symbols it does so with them all in uppercase.  Uppercase is a little… SHOUTY! …however, so in his SomeDegreeOfIntrospection package Sture changed those uppercase struct member names to lowercase.  This does not cause a problem when we are using them to interpret inbound JSON data, because we simply make the comparisons we are doing case-insensitive by uppercasing both sides (although it would have a problem with data where there were members of the same object which were only distinguished by casing – a very unlikely situation).  When it comes to generating outbound JSON however, this loss of casing shows itself in the fact that all of our property names have become lowercase.

This is probably not a show-stopper in most circumstances, but we need to be aware of it when accessing those properties in case-sensitive JavaScript.  Given that this is only a temporary solution until Data Access build full support for JSON (and perhaps for JSONP) into the product, it is probably “good enough” for most situations.

So, with all now explained, please feel free to explore the JSONP sample.