[TotW] JSON-RPC and Other JSON Enhancements

The tip of the week for September 28, 2007 introduces support in Lasso for the lightweight JSON-RPC protocol including a [JSON_RPCCall] tag and built-in support for calling JSON-RPC tags through the RPC.LassoApp. The tip also includes several enhancements to Lasso's JSON tags: new [Object] and [Literal] types which make it easier to create JavaScript objects and a new native type embedding method.

Introduction

JSON (JavaScript Object Notation) is a lightweight method of passing data between servers on the Internet. JSON encoded values are specified as either a JavaScript array (e.g. [1, 2, 3, 4]) or a JavaScript object (e.g. {"name": "value"}) which is similar to a Lasso [Map]. JSON requires considerably less overhead than SOAP or XML formats. JSON was discussed in this prior tip of the week.

  <http://www.lassosoft.com/Documentation/TotW/index.lasso?9268>

More information about JSON can be found on the following pages:

  <http://www.json.org/>
  <http://www.ietf.org/rfc/rfc4627.txt>

JSON-RPC (JSON Remote Procedure Call) is a lightweight method of calling procedures on other servers using a JSON-specified request and response. JSON-RPC is an alternative to using XML-RPC or SOAP for communication between servers. This tip includes a JSON.Lasso file which implements a [JSON_RPCCall] tag that can be used to make a JSON-RPC call on a remote server as well as a new RPC.LassoApp file which allows Lasso to automatically serve JSON-RPC requests.

More information about JSON-RPC can be found on the following pages. The JavaScript O Lait page has a test server which was used to test the JSON-RPC implementation presented in this tip.

  <http://json-rpc.org/>
  <http://jsolait.net/wiki/examples/jsonrpc/tester>

Download and Installation

The files for this tip can be download from the following URL and run in any copy of Lasso 8.5.4.

  <http://download.lassosoft.com/pub/totw/TotW_9319.zip>

- LassoApps - The RPC.LassoApp file should be placed into the LassoApps folder within the Lasso Professional application folder or an individual site folder.

- LassoStartup - The JSON.Lasso file should be placed into the LassoStartup folder within the Lasso Professional application folder or an individual site folder.

- Restart Lasso Service to load these files.

- JSON - The JSON folder should be placed into your Web server root and the index.lasso file inside loaded through a Web browser using the following URL. The source code of this file can be examined to see how the [Encode_JSON], [Decode_JSON], and [JSON_RPCCall] tags are coded.

  <http://localhost/JSON/index.lasso>

- LassoApps Source - This folder contains the source code for the RPC.LassoApp so you can see how JSON-RPC support was added to the RPC.lasso file.

JSON-RPC

JSON-RPC is a very simple protocol which consists of two types of messages. A request consists of a method (procedure or tag name), parameters, and a unique ID. A response consists of the results of the method, an error code/message, and the ID of the request which generated the response.

JSON-RPC communication may occur through low-level TCP communication. The idea is that requests are sent through individually, each with a unique ID. The responses to those requests can come back in any order, with the ID allowing each to be routed appropriately within the client.

The [JSON_RPCCall] tag implemented for this tip uses a simpler HTTP protocol. A single JSON-RPC request is sent as the POST parameter for an HTTP call. The connection is held open until a single response is returned.

A JSON-RPC request appears as follows. The entire request is encoded as a single JSON object. The method in this case is "echo" which will echo back a single parameter as the result. The parameters are specified as a JSON array. The ID is specified as a unique integer.

  {"method": "echo", "params":["Hello World!"], "id":1234}

This request could be created in Lasso using the following code:

  [Encode_JSON: (Map:
      'method'='echo',
      'params'=(Array: 'Hello World!'),
      'id'=1234)]

The request could be transmitted to a remote server using [Include_URL], passing the encoded request object as the -PostParams.

  [Include_URL: 'http://localhost/RPC.LassoApp',
    -PostParams=(Encode_JSON: ...)]

The response for the request appears as follows. The entire response is encoded as a single JSON object. The result can be of any type. The error is Null since the request succeeded. The ID matches that which was sent with the request.

  {"result": "Hello World!", "error": null, "id":1234}

The following code uses a test JSON-RPC server at JavaScript O Lait to actually run the "echo" method. The result is a Lasso map which corresponds to the response shown above.

  [Decode_JSON: (Include_URL: 'http://jsolait.net/services/test.jsonrpc',
    -PostParams=(Encode_JSON: (Map:
        'method'='echo',
        'params'=(Array: 'Hello World!'),
        'id'=1234)))]
   map: (error)=(), (id)=(1234), (result)=(Hello World!)

The next section will describe how to create a JSON-RPC method on your Lasso server. The following sections will show how to use [JSON_RPCCall] to call JSON-RPC methods on either the local server or other servers.

Defining a JSON Procedure

Lasso has a built-in method of defining XML-RPC methods. The RPC.LassoApp included in the download for this tip extends this functionality so the same methods will be available through JSON-RPC. To define an RPC method simply include the -RPC keyword in [Define_Tag]. The following code defines a new RPC method "echo".

  [Define_Tag: 'echo', -RPC, -Required='value']
    [Return: #value]
  [/Define_Tag]

The tag will not be available as [Echo: 'test'], but will be available to be called through the RPC.LassoApp by a remote client.

Calling a Local JSON Procedure

Once we define a new RPC method we can call it using the [JSON_RPCCall] tag. This tag requires a -Method that specifies which procedure to call. Parameters can be specified as an array to the -Params parameter. An optional -ID can be specified (otherwise a unique ID will be generated).

The RPC method "echo" can be called as follows. The result as shown below. It contains the message which was echoed, a null error object, and the ID which was passed.

  [JSON_RPCCall: -Method='echo', -Params=(Array: 'Hello World!'), -ID=1234]
   map: (error)=(), (id)=(1234), (result)=(Hello World!)

If an error occurs then it will be reported in the error object. Lasso reports the error code and message in a map. Other servers might report their errors using an object with different keys or a simple error code or message.

   map: (error)=(map: (code)=(-9956), (msg)=(The tag 'echo' expected a parameter 'value', but none was provided.)), (id)=(1), (result)=()

Calling a Remote JSON Procedure

The [JSON_RPCCall] tag can be used to call a remote procedure by passing a -Host parameter with the path to the remote procedure page or CGI. The "echo" method on the test server at JavaScript O Lait can be called as follows. The result is the same as for the local call above.

  [JSON_RPCCall: -Method='echo', -Params=(Array: 'Hello World!'), -ID=1234,
      -Host='http://jsolait.net/services/test.jsonrpc']
   map: (error)=(), (id)=(1234), (result)=(Hello World!)

Native Data Types

The JSON-RPC standard defines a new method of encoding native data types. This method has been adopted by the [Encode_JSON] tag included in the download for this tip in order to provide a more universal method of embedding Lasso's native data types. Each native type is encoded as a JSON object with a __jsonclass__ element whose value is an array. The first element of the array is the name of a constructor which can recreate the type, the second element is an array of parameters which should be passed to the constructor. Any other elements of the object are properties which are applied to the native data type after it has been created.

  {"__jsonclass__":["constructor", [param1,...]], "prop1": ...}

Lasso data types are encoded using a constructor of "deserialize" with the XML serialization as the only parameter and no properties. A Lasso data type which cannot be encoded directly into an equivalent JSON construct will appear as follows.

  [{"__jsonclass__": ["deserialize", ["<LassoNativeType> ... </LassoNativeType>"]]}]

The JSON.Lasso file included with the download files encodes data types using the format shown above, but can decode the earlier implementations for backward compatibility with different versions of the JSON.Lasso file.

JSON Enhancements

This tip includes a new version of the JSON.Lasso file which implements the [JSON_RPCCall] tag, but also has a few other enhancements.

JSON can be used to create JavaScript objects and arrays for use in scripts on the current page. However, sometimes it is necessary to include literal values in these scripts rather than quoted strings.

The [Literal] data type is a simple subtype of [String] which will be formatted without any encoding or quote marks when passed through [Encode_JSON]. One common use of [Literal] is to insert function definitions or variable references into an object without any string encoding. You can see in the output that the function is passed through without any changes.

  [Encode_JSON: (Map: 'action'='click', 'fn'=(Literal: 'function(){ ... }'))]
   {"fn": function(){ ... }, "action": "click"}

The [Object] data type is a simple subtype of [Map] for which all the keys will be formatted as literals. Objects in JavaScript are normally written without quote marks on the keys so this makes the code look proper when used in local scripts. The same object defined above can be output as an [Object] as follows. Note that the object's element keys are not quoted.

  [Encode_JSON: (Object: 'action'='click', 'fn'=(Literal: 'function(){ ... }'))]
   {fn: function(){ ... }, action: "click"}

Note - These tags should be used only when encoding values for local JavaScripts. They should not be used when passing JSON messages to remote servers. They do not adhere to the JSON standard.

More Information

More information about all of the tags used in this tip of the week can be found in the Lasso 8.5 Language Guide or in the online Lasso Reference <http://reference.lassosoft.com/>.