Sending a JSON-RPC request
Before sending any request, you should have already established a connection.
Requests and notifications
Within the JSON-RPC specification, a client request can specify whether a reply from the server is required. If no reply is expected, the message is a notification. Because notifications do not generate responses, the client receives no confirmation that the server received the request, processed it successfully, encountered an error, or produced any output.
A notification should not be used just because a method does not return a value. Even when a method has no return data, using the standard request-response model ensures the client can detect failures or execution errors on the server side.
Argument arrays vs. an argument object
The JSON-RPC protocol passes arguments from client to server using either an array or as a single JSON object with a property for each parameter on the target method. Essentially, this leads to argument-to-parameter matching by position or by name.
Most JSON-RPC servers expect an array. json_rpc supports passing arguments both as a parameter object and in an array.
Invoking methods using compile-time definitions
The createRpcSigsFromNim macro accepts a list of forward procedure declarations and it generates the client RPCs. The RpcConv defined in the flavors section is used in the following example:
createRpcSigsFromNim(RpcClient, RpcConv):
proc hello(input: string): string
Wrapping the method name in backticks allows any character:
proc `🙂`(input: string): string
The RPC method can be invoked using a client instance with a stablished connection:
let resp1 = await client.hello("Daisy")
The createRpcSigs macro accepts the path of a file containing a list of forward proc declarations and it generates the client RPCs of it:
const sigsFilePath = currentSourcePath().parentDir / "client_sigs.nim1"
createRpcSigs(RpcClient, sigsFilePath, RpcConv)
The createSingleRpcSig macro accepts a single forward proc declaration and an alias. The alias can be used to invoke the RPC method:
createSingleRpcSig(RpcClient, "sayBye", RpcConv):
proc bye(input: string): string
The createRpcSigsFromString macro accepts a string containing a list of forward proc declarations and it generates the client RPCs:
const rpcClientDefs = staticRead(sigsFilePath)
createRpcSigsFromString(RpcClient, rpcClientDefs, RpcConv)
Invoking methods using runtime information
An RPC method can be invoked passing its name an parameter types at runtime. The parameter must be passed as a JsonNode or RequestParamsTx. The RpcConv defined in the flavors section is used in the following example:
let resp2 = await client.call("hello", %* ["Daisy"], RpcConv)
Using named parameters is allowed. Some server implementations may support only positional parameters, json_rpc supports both styles:
let resp3 = await client.call("hello", %* {"input": "Daisy"}, RpcConv)
When the method doesn't take parameters, it can be invoked passing an empty array:
let resp4 = await client.call("justHello", %* [], RpcConv)
The response from call is a JsonString which can be decoded using json_serialization:
doAssert RpcConv.decode(resp2, string) == "Hello Daisy"
Sending batch requests
The JSON-RPC specification allows for batching requests and getting a response containing an array of responses for each request.
The prepareBatch client function can be used to batch requests and send them all at once:
let batch = client.prepareBatch()
batch.hello("Daisy")
batch.`🙂`("Daisy")
let batchRes = await batch.send()
The send return value is an optional result with either the sequence of RPC responses, or an error indicating there was an error processing the array of responses. Each response contains a result or an error. The result field is the JSON encoded RPC result. If the optional error field is set, it'll contain either an error message or the JSON encoded RPC error response:
let r = batchRes.tryGet()
doAssert r[0].error.isNone
doAssert RpcConv.decode(r[0].result, string) == "Hello Daisy"
doAssert r[1].error.isNone
doAssert RpcConv.decode(r[1].result, string) == "🙂 Daisy"
Sending a notification
A notification can be sent for fire and forget method invocations. As mentioned earlier, the method response is not returned, and the client is not notified about server errors:
await client.notify("empty", RequestParamsTx())
Exception handling
RPC methods may throw exceptions. The RPC client should be prepared to handle these exceptions.