Implementation decisions for my JSON-RPC client (part 1)

Welcome to the second blog post of this series consacred to my project of a JSON-RPC client implementation in Haskell (the first post may be consulted here).

What are the implementation choices ?

I had to choose between version 1 and version 2 of the protocol. I have chosen to implement both versions using the second version as the default protocol. The reasons for this choice were the following:

  • Most other implementations support version 2, so there’s not a great incentive not to implement version 2. However, you might be forced to work with a legacy server, like I had been during my tests. Thus, having also version 1 is a Good Idea™.
  • Annoyingly enough, version 1 mandates the existence of an error object but doesn’t specify required fields…
  • Yet another annoyance concerns ids, version 1 specifies that a method call id is of any type but mandates that a notification id be of null type. This slight imprecision is usually dealt with by using only non-null ids as call ids, but still… To be fair, version 2 is also annoying here: a method call id is a number, a string or null but a null id must be attributed to syntactically incorrect requests. This “problem” is dealt with by, once again, using only non-null ids.

I do not, for the time being, implement batch requests (given that the API map an Haskell function call to a JSON-RPC communication), neither do I implement positional arguments, nor do I implement other transports than HTTP POST requests. I might in the future try to adapt the API to support batch requests and to support other transports (HTTP GET, TCP streams…)

What is the API ?

The API, as well as the code, was heavily inspired by HaXR (which, if you think about it is only fitting given JSON-RPC was inspired by XML-RPC)
Exposed to the client, there are two typeclasses: JsonRpcCall (representing remote calls) and JsonRpcNotification (representing notifications). Both serve to retrieve and marshal the remote function’s parameters, call it and, in JsonRpcCall‘s case, retrieve and unmarshal the result. Both have an instance for functions taking an instance of ToJSON (that is, a type marshallable to JSON, this typeclass comes from aeson) and returning an instance of the typeclass. JsonRpcCall has also an instance for (FromJSON a) => IO a (type unmarshallable from JSON, lifted in IO, also comes from aeson) and JsonRpcNotification has an instance for IO (), which is normal given a notification doesn’t care about the server answer. The IO part of the return type shouldn’t be a surprise: after all, they take their result from the network…
There are also two data types: JsonRpcVersion representing the protocol’s version used in a given call and JsonRpcException representing errors in JSON-RPC, be that errors in the remote functions usage, in the (un)marshalling of the messages, or even type mismatches between the remote function and its caller.
Finally, there are four functions: remote and notify which generate a remote call (resp. notification) using JSON-RPC version 2, HTTP POST as transport protocol and without custom elements in the generated JSON. Their signatures should always be explicit: they take two Strings in arguments (the server’s URL and the method’s name) and return a JsonRpcCall (resp. JsonRpcNotification). The other two are detailledRemote and detailledNotify which take, before the two Strings taken by the basic versions, a JsonRpcVersion and a [Pair], representing respectively the protocol version used for this call and the key-element pairs to be added to the JSON object representing the request, in addition to the standards elements.

And after ?

The next blog post in this series will talk about the details of the implementation of this client, and how to use it.
In the meantime, you may find the source code of the client here.

Advertisements

What is JSON-RPC ?

Welcome to the first blog post of this series consacred to my project of a JSON-RPC client implementation in Haskell.

Definition and description

JSON-RPC is a lightweight RPC protocol defining an encoding, JSON, and a transport, HTTP. It also defines notifications, requests not needing a response, and the protocol’s second version defines another possible transport, TCP/IP sockets, and a means of batching calls and notifications. However, due to its simplicity, it does not define neither authentication nor means of querying the server about implemented functions.

Why will I implement it ?

First of all, I’ll implement it because it is a simple textual RPC protocol, specifiying an already implemented in Haskell transport protocol. Another reason is that’s there are many implementations of this protocol, giving me the possibility to test my client against an already existing server. And it serves as a test of my capacities as an Haskell developper and as a spec reader. And there’s the fact that previous experience have told me that trying to tackle everything at once in my quest to be a better Haskell programmer is a bad idea: I’ll start with networking (without taking care of protocol details)… I’ll leave writing the network encoder and taking care of low level details to my next project…

Why Haskell ?

Cf. my post on RFC 707.

And after ?

The next blog post in this series will be consacred to the API my library will have and to the implementation choices I’ll make. After all, I have to choose between two versions of the protocol.

After this project, I’ll probably get back to my project of an RFC 707 implementation.

Projects list

Featured

Here are the list of my projects featured in this blog, with their status:

  • JSON-RPC client implementation in Haskell (started: repo is here)
  • RFC 707 implementation in Haskell (on hold)
  • ONC RPC client implementation in Haskell (not started)
  • AWT implementation in curses, using caciocavallo (not started)
  • Haskell compiler in Haskell (not started)
  • file(1) implementation using shared-mime-info as its source of information (started: see here) That project's in Perl.

For the time being, all my projects are on hold or not even started due to my studies…I will however talk about my RFC 707 implementation project, given it already started.

N.B. : I may do some of these projects also in other languages (e.g. Perl) if the fancy takes me.