JSON-RPCUser Guide

Overview

An implementation of the JSON-RPC v2.0 specification.

JSON-RPC is used by the Language Server Protocol (LSP) to serialise messages.

Use JSON-RPC to invoke methods on a class instance.

Quick Start

using afJsonRpc

class Example {

    Void main() {
        sink    := ExampleSink()  // this will receive the method calls
        jsonRpc := JsonRpc(sink)

        // rpc call with positional parameters
        res1 := jsonRpc.call(
             """{
                    "jsonrpc": "2.0",
                    "id"     : 1,
                    "method" : "subtract",
                    "params" : [42, 23]
                }""".in
        )
        echo(res1)
        // <-- {"jsonrpc": "2.0", "result": 19, "id": 1}

        // rpc call with named parameters
        res2 := jsonRpc.call(
             """{
                    "jsonrpc": "2.0",
                    "id"     : 3,
                    "method" : "subtract",
                    "params" : {"subtrahend": 23, "minuend": 42}
                 }""".in
        )
        echo(res2)
        // <-- {"jsonrpc": "2.0", "result": 19, "id": 3}
    }
}

class ExampleSink {
    Float subtract(Float minuend, Float subtrahend) {
        return minuend - subtrahend
    }
}

Multiple Sinks

For larger RPC implementations you will want multiple sinks for your methods. For this, pass a Str:Obj map to JsonRpc where the Objs are the sinks, and the Strs are a matching prefix.

jsonRpc := JsonRpc([
    "text/"  : TextSink()
    "image/" : ImageSink()
])

Then the RPC call {"jsonrpc": "2.0", "method": "text/update"} would be forwarded to the method TextSink.update().

And the RPC call {"jsonrpc": "2.0", "method": "image/update"} would be forwarded to the method ImageSink.update().

For optimised calls, use a custom dispatchFn:

JsonRpc(..., [
    "dispatchFn" : JsonRpc.multiSinkDispatchFn('/')
])

Transport over HTTP

Use afBedSheet to create a HTTP server for receive your RPC calls.

JSON to Fantom object mapping

Use afJson to map JSON to Fantom objects.

json    := afJson::JsonConverters()
jsonRpc := JsonRpc(..., [
    "invokeFn" : JsonRpc.convertingInvokeFn |type, val| {
        type != null ? json.fromJsonVal(val, type) : json.toJsonVal(val)
    }
])