dwayne / elm-json-rpc / JsonRpc

Send JSON-RPC 2.0 requests over HTTP.

The implementation is guided by the following specifications:

Construct a request


type alias Request result =
{ method : String
, params : Params
, result : Json.Decode.Decoder result 
}

An RPC call is represented by sending a Request object to a server. This Request record is used to create a Request object.

For example, the following Request record:

import Json.Decode as JD
import Json.Encode as JE
import JsonRpc

getBalance : JsonRpc.Request String
getBalance =
    { method = "eth_getBalance"
    , params =
        JsonRpc.positionalParams
            [ JE.string "0x0000000000000000000000000000000000000000"
            , JE.string "latest"
            ]
    , result = JD.string
    }

corresponds to the following Request object:

{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [ "0x0000000000000000000000000000000000000000", "latest" ],
    "id": ...
}

And, on a successful response the result field is expected to contain a String.

Note: The id field is set when sending the request.


type Params

A JSON Array or Object that holds the parameter values to be used during invocation of an RPC method.


type alias Param =
Json.Encode.Value

A JSON value.

noParams : Params

An empty JSON Array.

positionalParams : List Param -> Params

A JSON Array containing the parameter values in the server expected order.

For example, the following:

import Json.Encode as JE
import JsonRpc

JsonRpc.positionalParams
    [ JE.string "0x0000000000000000000000000000000000000000"
    , JE.string "latest"
    ]

represents the JSON Array:

[ "0x0000000000000000000000000000000000000000", "latest" ]

namedParams : List ( String, Param ) -> List ( String, Maybe Param ) -> Params

A JSON Object with member names that match the server expected parameter names.

For example, the following:

import Json.Encode as JE
import JsonRpc

JsonRpc.namedParams
    [ ( "apiKey", JE.string "YOUR API KEY"
    , ( "n", JE.int 5 )
    , ( "min", JE.int 1 )
    , ( "max", JE.int 10 )
    ]
    [ ( "replacement", Just False )
    ]

represents the JSON Object:

{
    "apiKey": "YOUR API KEY",
    "n": 5,
    "min": 1,
    "max": 10,
    "replacement": false
}

Send a request

send : String -> (Result Error result -> msg) -> Request result -> Platform.Cmd.Cmd msg

Sends a Request object over HTTP to a JSON-RPC server with a default request identifier of 1.

import JsonRpc

type Msg
    = GotBalance (Result JsonRpc.Error String)

let
    rpcUrl =
        "https://eth-goerli.public.blastapi.io"
in
JsonRpc.send rpcUrl GotBalance getBalance

The Request object:

{
    "jsonrpc": "2.0",
    "method": "eth_getBalance",
    "params": [ "0x0000000000000000000000000000000000000000", "latest" ],
    "id": 1
}

will be sent over HTTP to the JSON-RPC server at the endpoint https://eth-goerli.public.blastapi.io.

Send a request with a custom identifier


type Id

An identifier established by you.

intId : Basics.Int -> Id

An integer identifier.

stringId : String -> Id

A string identifier. Maybe you'd want to use a UUID as your identifier.

import JsonRpc

JsonRpc.stringId "789e08a1-6156-4046-88b6-5b96a87a2eba"

sendWithId : String -> (Result Error result -> msg) -> Id -> Request result -> Platform.Cmd.Cmd msg

Just like send, but it allows you to set the identifier.

Advanced


type alias HttpOptions =
{ headers : List Http.Header
, timeout : Maybe Basics.Float
, tracker : Maybe String 
}

The HTTP options you're allowed to modify.

defaultHttpOptions : HttpOptions

The default HTTP options used by send and sendWithId.

{ headers = []
, timeout = Nothing
, tracker = Nothing
}

sendCustom : HttpOptions -> String -> (Result Error result -> msg) -> Id -> Request result -> Platform.Cmd.Cmd msg

Just like sendWithId, but it allows you to customize the HTTP options.

import JsonRpc exposing (defaultHttpOptions)

type Msg
    = GotBalance (Result JsonRpc.Error String)

let
    httpOptions =
        -- wait 1 minute
        { defaultHttpOptions | timeout = Just 60000 }

    rpcUrl =
        "https://eth-goerli.public.blastapi.io"

    id =
        JsonRpc.stringId "abc123"
in
JsonRpc.sendCustom httpOptions rpcUrl GotBalance id getBalance

Error


type Error
    = HttpError HttpError
    | UnexpectedStatus Http.Metadata String
    | DecodeError Json.Decode.Error
    | MismatchedIds ({ requestId : String, responseId : String })
    | JsonRpcError ({ kind : Kind, code : Basics.Int, message : String, maybeData : Maybe Json.Encode.Value, responseId : String })

A request can fail in multiple ways.


type HttpError
    = BadUrl String
    | Timeout
    | NetworkError
    | BadStatus Http.Metadata String

The HTTP transport can fail in multiple ways.


type Kind
    = ParseError
    | InvalidRequest
    | MethodNotFound
    | InvalidParams
    | InternalError
    | ServerError
    | ReservedError
    | ApplicationError

This data type categorizes the error code of a failed RPC call.

The categories are derived from the specification as given by the table under the Error object section.