JSON-RPC 2.0 vs 1.0

JSON-RPC 2.0Users of my Json2Ldap gateway/proxy software have noticed that its client interface is based on the latest version 2.0 of the JSON-RPC protocol (actually, the 2.0 specification proposal from 2010-03-26 which has stabilised now). Version 1.0 isn’t supported at all. Why is that and what are the advantages of JSON-RPC 2.0 over 1.0?

Version 2.0 brings a number of changes to the protocol, but its single most significant new feature, for services having the API complexity of Json2Ldap and JsonSSO, are the so-called named parameters.

The original version of JSON-RPC allows for parameter passing just like the function arguments in computer languages such as C and Java – the RPC parameters are identified by their position in the enclosing JSON array, that is we have positional parameters.

Here is one JSON-RPC 1.0 request example, notice the 3 parameters:

{ "method" : "registerUser", 
  "params" : ["uid001", "Adam Brown", "abrown@example.com"], 
  "id" : 0 }

Positional parameters are great for simple method signatures that include mostly mandatory parameters and API’s that are not expected to change much in future. If you, however, have methods with numerous optional parameters, or expect to support new optional parameters in future, then using positional parameters quickly becomes impractical.

Consider for example the ldap.search call of Json2Ldap. It has a fairly complex set of parameters, with 4 mandatory and 6 optional ones:

  • Mandatory parameters: CID, baseDN, scope, filter
  • Optional parameters: attributes, derefPolicy, sizeLimit, timeLimit, typesOnly, output

A method signature using positional parameters lists the mandatory first, followed by the optional ones, preferably in an order of decreasing parameter usage. An example ldap.search request, JSON-RPC 1.0 style, with mandatory parameters only:

{ "method" : "ldap.search", 
  "params" : ["26009f7f10b38b92ca0a8744b825104f", 
              "ou=people,dc=example,dc=com", 
              "SUB",
              "(sn=Brown)"], 
   "id" : 0 }

Now the same request as above, but also specifying a value for the last optional parameter (output type = LDIF). The preceding optional parameters are passed a null to leave them at their default value.

{ "method" : "ldap.search", 
  "params" : ["26009f7f10b38b92ca0a8744b825104f", 
              "ou=people,dc=example,dc=com", 
              "SUB",
              "(sn=Brown)",
              null,
              null,
              null,
              null,
              null,
              "LDIF"], 
   "id": 0 }

Having to fill in a number of nulls for each optional parameter until we got to the optional parameter that we wanted to specify is not particularly elegant, in fact it can be error prone too. While this example may be somewhat extreme the point I wanted to make should be clear now – JSON-RPC 1.0 with its positional-parameters-only model doesn’t serve well methods with multiple optional parameters.

That’s why in summer 2009 I was delighted to find out that an improved JSON-RPC standard had been in the works, called “2.0”, bringing one really neat feature – named parameters. It allows for an alternative parameter passing method where the values are packed as members of a JSON object. Order becomes irrelevant now as each parameter is specified by name.

Yes, named parameters make JSON-RPC requests more verbose, but I think this is rather good: the requests become self-describable which helps debugging, readability and even logging.

Therefore it was a straightforward decision to settle on a JSON-RPC 2.0 interface for the Json2Ldap gateway/proxy. The 2.0 draft has significantly stabilised now and I don’t expect any changes apart from minor wording corrections by the time it becomes “official”.

Here is a repeat of the above two ldap.search calls to Json2Ldap, but using named parameters now:

{ "method" : "ldap.search", 
  "params" : {"CID":"26009f7f10b38b92ca0a8744b825104f", 
              "baseDN":"ou=people,dc=example,dc=com", 
              "scope":"SUB",
              "filter":"(sn=Brown)"}, 
   "id" : 0,
   "jsonrpc" : "2.0" }

And the request with the optional “output” parameter:

{ "method" : "ldap.search", 
  "params" : {"CID":"26009f7f10b38b92ca0a8744b825104f", 
              "baseDN":"ou=people,dc=example,dc=com", 
              "scope":"SUB",
              "filter":"(sn=Brown)"
              "output":"LDIF"}, 
   "id" : 0,
   "jsonrpc" : "2.0" }

Yes, the JSON-RPC requests look neater now with named parameters!. And as I mentioned before, readability is top too!

The JSON-RPC 2.0 improvements are not limited to adding named parameter support. The protocol was streamlined by removing some transport dependencies and specification redundancies. Also, the error reporting of common conditions (parse error, etc.) was standardised. All this makes JSON-RPC 2.0 a highly attractive choice for lightweight web communications.

PS: For my JSON-RPC 2.0 based projects I have developed my own Java implementation, called JsonRpc2 Base. It can be used both on the server and client sides and is deliberately kept as simple and minimal as possible (no frameworks, batching left out). While the software is not exactly free, its price is also minimal. The package comes with generous license terms, full source code and carefully written documentation. JsonRpc2 Base has been through a number of refinements and its current version is 1.9.1.