README

Go Report Card GoDoc GitHub license

JSON-RPC 2.0 Client for golang

A go implementation of an rpc client using json as data format over http. The implementation is based on the JSON-RPC 2.0 specification: http://www.jsonrpc.org/specification

Supports:

  • requests with arbitrary parameters
  • convenient response retrieval
  • batch requests
  • custom http client (e.g. proxy, tls config)
  • custom headers (e.g. basic auth)

Installation

go get -u github.com/ybbus/jsonrpc

Getting started

Let's say we want to retrieve a person struct with a specific id using rpc-json over http. Then we want to save this person after we changed a property. (Error handling is omitted here)

type Person struct {
    Id   int `json:"id"`
    Name string `json:"name"`
    Age  int `json:"age"`
}

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")

    var person *Person
    rpcClient.CallFor(&person, "getPersonById", 4711)

    person.Age = 33
    rpcClient.Call("updatePerson", person)
}

In detail

Generating rpc-json requests

Let's start by executing a simple json-rpc http call: In production code: Always make sure to check err != nil first!

This calls generate and send a valid rpc-json object. (see: http://www.jsonrpc.org/specification#request_object)

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    rpcClient.Call("getDate")
    // generates body: {"method":"getDate","id":1,"jsonrpc":"2.0"}
}

Call a function with parameter:

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    rpcClient.Call("addNumbers", 1, 2)
    // generates body: {"method":"addNumbers","params":[1,2],"id":1,"jsonrpc":"2.0"}
}

Call a function with arbitrary parameters:

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    rpcClient.Call("createPerson", "Alex", 33, "Germany")
    // generates body: {"method":"createPerson","params":["Alex",33,"Germany"],"id":1,"jsonrpc":"2.0"}
}

Call a function providing custom data structures as parameters:

type Person struct {
  Name    string `json:"name"`
  Age     int `json:"age"`
  Country string `json:"country"`
}
func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    rpcClient.Call("createPerson", &Person{"Alex", 33, "Germany"})
    // generates body: {"jsonrpc":"2.0","method":"createPerson","params":{"name":"Alex","age":33,"country":"Germany"},"id":1}
}

Complex example:

type Person struct {
  Name    string `json:"name"`
  Age     int `json:"age"`
  Country string `json:"country"`
}
func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    rpcClient.Call("createPersonsWithRole", &Person{"Alex", 33, "Germany"}, &Person{"Barney", 38, "Germany"}, []string{"Admin", "User"})
    // generates body: {"jsonrpc":"2.0","method":"createPersonsWithRole","params":[{"name":"Alex","age":33,"country":"Germany"},{"name":"Barney","age":38,"country":"Germany"},["Admin","User"]],"id":1}
}

Some examples and resulting JSON-RPC objects:

rpcClient.Call("missingParam")
{"method":"missingParam"}

rpcClient.Call("nullParam", nil)
{"method":"nullParam","params":[null]}

rpcClient.Call("boolParam", true)
{"method":"boolParam","params":[true]}

rpcClient.Call("boolParams", true, false, true)
{"method":"boolParams","params":[true,false,true]}

rpcClient.Call("stringParam", "Alex")
{"method":"stringParam","params":["Alex"]}

rpcClient.Call("stringParams", "JSON", "RPC")
{"method":"stringParams","params":["JSON","RPC"]}

rpcClient.Call("numberParam", 123)
{"method":"numberParam","params":[123]}

rpcClient.Call("numberParams", 123, 321)
{"method":"numberParams","params":[123,321]}

rpcClient.Call("floatParam", 1.23)
{"method":"floatParam","params":[1.23]}

rpcClient.Call("floatParams", 1.23, 3.21)
{"method":"floatParams","params":[1.23,3.21]}

rpcClient.Call("manyParams", "Alex", 35, true, nil, 2.34)
{"method":"manyParams","params":["Alex",35,true,null,2.34]}

rpcClient.Call("singlePointerToStruct", &person)
{"method":"singlePointerToStruct","params":{"name":"Alex","age":35,"country":"Germany"}}

rpcClient.Call("multipleStructs", &person, &drink)
{"method":"multipleStructs","params":[{"name":"Alex","age":35,"country":"Germany"},{"name":"Cuba Libre","ingredients":["rum","cola"]}]}

rpcClient.Call("singleStructInArray", []*Person{&person})
{"method":"singleStructInArray","params":[{"name":"Alex","age":35,"country":"Germany"}]}

rpcClient.Call("namedParameters", map[string]interface{}{
	"name": "Alex",
	"age":  35,
})
{"method":"namedParameters","params":{"age":35,"name":"Alex"}}

rpcClient.Call("anonymousStruct", struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}{"Alex", 33})
{"method":"anonymousStructWithTags","params":{"name":"Alex","age":33}}

rpcClient.Call("structWithNullField", struct {
	Name    string  `json:"name"`
	Address *string `json:"address"`
}{"Alex", nil})
{"method":"structWithNullField","params":{"name":"Alex","address":null}}
Working with rpc-json responses

Before working with the response object, make sure to check err != nil. Also keep in mind that the json-rpc result field can be nil even on success.

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    response, err := rpcClient.Call("addNumbers", 1, 2)
    if err != nil {
      // error handling goes here e.g. network / http error
    }
}

If an http error occurred, maybe you are interested in the error code (403 etc.)

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    response, err := rpcClient.Call("addNumbers", 1, 2)

    switch e := err.(type) {
      case nil: // if error is nil, do nothing
      case *HTTPError:
        // use e.Code here
        return
      default:
        // any other error
        return
    }

    // no error, go on...
}

The next thing you have to check is if an rpc-json protocol error occurred. This is done by checking if the Error field in the rpc-response != nil: (see: http://www.jsonrpc.org/specification#error_object)

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    response, err := rpcClient.Call("addNumbers", 1, 2)
    if err != nil {
        //error handling goes here
    }

    if response.Error != nil {
        // rpc error handling goes here
        // check response.Error.Code, response.Error.Message and optional response.Error.Data
    }
}

After making sure that no errors occurred you can now examine the RPCResponse object. When executing a json-rpc request, most of the time you will be interested in the "result"-property of the returned json-rpc response object. (see: http://www.jsonrpc.org/specification#response_object) The library provides some helper functions to retrieve the result in the data format you are interested in. Again: check for err != nil here to be sure the expected type was provided in the response and could be parsed.

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    response, _ := rpcClient.Call("addNumbers", 1, 2)

    result, err := response.GetInt()
    if err != nil {
        // result cannot be unmarshalled as integer
    }

    // helpers provided for all primitive types:
    response.GetInt()
    response.GetFloat()
    response.GetString()
    response.GetBool()
}

Retrieving arrays and objects is also very simple:

// json annotations are only required to transform the structure back to json
type Person struct {
    Id   int `json:"id"`
    Name string `json:"name"`
    Age  int `json:"age"`
}

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    response, _ := rpcClient.Call("getPersonById", 123)

    var person *Person
    err := response.GetObject(&person) // expects a rpc-object result value like: {"id": 123, "name": "alex", "age": 33}
    if err != nil || person == nil {
        // some error on json unmarshal level or json result field was null
    }

    fmt.Println(person.Name)

    // we can also set default values if they are missing from the result, or result == null:
    person2 := &Person{
        Id: 0,
        Name: "<empty>",
        Age: -1,
    }
    err := response.GetObject(&person2) // expects a rpc-object result value like: {"id": 123, "name": "alex", "age": 33}
    if err != nil || person2 == nil {
        // some error on json unmarshal level or json result field was null
    }

    fmt.Println(person2.Name) // prints "<empty>" if "name" field was missing in result-json
}

Retrieving arrays:

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    response, _ := rpcClient.Call("getRandomNumbers", 10)

    rndNumbers := []int{}
    err := response.GetObject(&rndNumbers) // expects a rpc-object result value like: [10, 188, 14, 3]
    if err != nil {
        // do error handling
    }

    for _, num := range rndNumbers {
        fmt.Printf("%v\n", num)
    }
}
Using convenient function CallFor()

A very handy way to quickly invoke methods and retrieve results is by using CallFor()

You can directly provide an object where the result should be stored. Be sure to provide it be reference. An error is returned if:

  • there was an network / http error
  • RPCError object is not nil (err can be casted to this object)
  • rpc result could not be parsed into provided object

One of te above examples could look like this:

// json annotations are only required to transform the structure back to json
type Person struct {
    Id   int `json:"id"`
    Name string `json:"name"`
    Age  int `json:"age"`
}

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")

    var person *Person
    err := rpcClient.CallFor(&person, "getPersonById", 123)

    if err != nil || person == nil {
      // handle error
    }

    fmt.Println(person.Name)
}

Most of the time it is ok to check if a struct field is 0, empty string "" etc. to check if it was provided by the json rpc response. But if you want to be sure that a JSON-RPC response field was missing or not, you should use pointers to the fields. This is just a single example since all this Unmarshaling is standard go json functionality, exactly as if you would call json.Unmarshal(rpcResponse.ResultAsByteArray, &objectToStoreResult)

type Person struct {
    Id   *int    `json:"id"`
    Name *string `json:"name"`
    Age  *int    `json:"age"`
}

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")

    var person *Person
    err := rpcClient.CallFor(&person, "getPersonById", 123)

    if err != nil || person == nil {
      // handle error
    }

    if person.Name == nil {
      // json rpc response did not provide a field "name" in the result object
    }
}
Using RPC Batch Requests

You can send multiple RPC-Requests in one single HTTP request using RPC Batch Requests.

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")

    response, _ := rpcClient.CallBatch(RPCRequests{
      NewRequest("myMethod1", 1, 2, 3),
      NewRequest("anotherMethod", "Alex", 35, true),
      NewRequest("myMethod2", &Person{
        Name: "Emmy",
        Age: 4,
      }),
    })
}

Keep the following in mind:

  • the request / response id's are important to map the requests to the responses. CallBatch() automatically sets the ids to requests[i].ID == i
  • the response can be provided in an unordered and maybe incomplete form
  • when you want to set the id yourself use, CallRaw()

There are some helper methods for batch request results:

func main() {
    // [...]

    result.HasErrors() // returns true if one of the rpc response objects has Error field != nil
    resultMap := result.AsMap() // returns a map for easier retrieval of requests

    if response123, ok := resultMap[123]; ok {
      // response object with id 123 exists, use it here
      // response123.ID == 123
      response123.GetObjectAs(&person)
      // ...
    }

}
Raw functions

There are also Raw function calls. Consider the non Raw functions first, unless you know what you are doing. You can create invalid json rpc requests and have to take care of id's etc. yourself. Also check documentation of Params() for raw requests.

Custom Headers, Basic authentication

If the rpc-service is running behind a basic authentication you can easily set the Authorization header:

func main() {
    rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{
   		CustomHeaders: map[string]string{
   			"Authorization": "Basic " + base64.StdEncoding.EncodeToString([]byte("myUser"+":"+"mySecret")),
   		},
   	})
    response, _ := rpcClient.Call("addNumbers", 1, 2) // send with Authorization-Header
}
Using oauth

Using oauth is also easy, e.g. with clientID and clientSecret authentication

func main() {
		credentials := clientcredentials.Config{
    		ClientID:     "myID",
    		ClientSecret: "mySecret",
    		TokenURL:     "http://mytokenurl",
    	}

    	rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{
    		HTTPClient: credentials.Client(context.Background()),
    	})

	// requests now retrieve and use an oauth token
}
Set a custom httpClient

If you have some special needs on the http.Client of the standard go library, just provide your own one. For example to use a proxy when executing json-rpc calls:

func main() {
	proxyURL, _ := url.Parse("http://proxy:8080")
	transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)}

	httpClient := &http.Client{
		Transport: transport,
	}

	rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{
		HTTPClient: httpClient,
	})

	// requests now use proxy
}
Expand ▾ Collapse ▴

Documentation

Overview

    Package jsonrpc provides a JSON-RPC 2.0 client that sends JSON-RPC requests and receives JSON-RPC responses using HTTP.

    Index

    Constants

    This section is empty.

    Variables

    This section is empty.

    Functions

    func Params

    func Params(params ...interface{}) interface{}

      Params is a helper function that uses the same parameter syntax as Call(). But you should consider to always use NewRequest() instead.

      e.g. to manually create an RPCRequest object: request := &RPCRequest{

      Method: "myMethod",
      Params: Params("Alex", 35, true),
      

      }

      same with new request: request := NewRequest("myMethod", "Alex", 35, true)

      If you know what you are doing you can omit the Params() call but potentially create incorrect rpc requests: request := &RPCRequest{

      Method: "myMethod",
      Params: 2, <-- invalid since a single primitive value must be wrapped in an array --> no magic without Params()
      

      }

      correct: request := &RPCRequest{

      Method: "myMethod",
      Params: []int{2}, <-- invalid since a single primitive value must be wrapped in an array
      

      }

      Types

      type HTTPError

      type HTTPError struct {
      	Code int
      	// contains filtered or unexported fields
      }

        HTTPError represents a error that occurred on HTTP level.

        An error of type HTTPError is returned when a HTTP error occurred (status code) and the body could not be parsed to a valid RPCResponse object that holds a RPCError.

        Otherwise a RPCResponse object is returned with a RPCError field that is not nil.

        func (*HTTPError) Error

        func (e *HTTPError) Error() string

          Error function is provided to be used as error object.

          type RPCClient

          type RPCClient interface {
          	// Call is used to send a JSON-RPC request to the server endpoint.
          	//
          	// The spec states, that params can only be an array or an object, no primitive values.
          	// So there are a few simple rules to notice:
          	//
          	// 1. no params: params field is omitted. e.g. Call("getinfo")
          	//
          	// 2. single params primitive value: value is wrapped in array. e.g. Call("getByID", 1423)
          	//
          	// 3. single params value array or object: value is unchanged. e.g. Call("storePerson", &Person{Name: "Alex"})
          	//
          	// 4. multiple params values: always wrapped in array. e.g. Call("setDetails", "Alex, 35, "Germany", true)
          	//
          	// Examples:
          	//   Call("getinfo") -> {"method": "getinfo"}
          	//   Call("getPersonId", 123) -> {"method": "getPersonId", "params": [123]}
          	//   Call("setName", "Alex") -> {"method": "setName", "params": ["Alex"]}
          	//   Call("setMale", true) -> {"method": "setMale", "params": [true]}
          	//   Call("setNumbers", []int{1, 2, 3}) -> {"method": "setNumbers", "params": [1, 2, 3]}
          	//   Call("setNumbers", 1, 2, 3) -> {"method": "setNumbers", "params": [1, 2, 3]}
          	//   Call("savePerson", &Person{Name: "Alex", Age: 35}) -> {"method": "savePerson", "params": {"name": "Alex", "age": 35}}
          	//   Call("setPersonDetails", "Alex", 35, "Germany") -> {"method": "setPersonDetails", "params": ["Alex", 35, "Germany"}}
          	//
          	// for more information, see the examples or the unit tests
          	Call(method string, params ...interface{}) (*RPCResponse, error)
          
          	// CallRaw is like Call() but without magic in the requests.Params field.
          	// The RPCRequest object is sent exactly as you provide it.
          	// See docs: NewRequest, RPCRequest, Params()
          	//
          	// It is recommended to first consider Call() and CallFor()
          	CallRaw(request *RPCRequest) (*RPCResponse, error)
          
          	// CallFor is a very handy function to send a JSON-RPC request to the server endpoint
          	// and directly specify an object to store the response.
          	//
          	// out: will store the unmarshaled object, if request was successful.
          	// should always be provided by references. can be nil even on success.
          	// the behaviour is the same as expected from json.Unmarshal()
          	//
          	// method and params: see Call() function
          	//
          	// if the request was not successful (network, http error) or the rpc response returns an error,
          	// an error is returned. if it was an JSON-RPC error it can be casted
          	// to *RPCError.
          	//
          	CallFor(out interface{}, method string, params ...interface{}) error
          
          	// CallBatch invokes a list of RPCRequests in a single batch request.
          	//
          	// Most convenient is to use the following form:
          	// CallBatch(RPCRequests{
          	//   Batch("myMethod1", 1, 2, 3),
          	//   Batch("myMethod2), "Test"),
          	// })
          	//
          	// You can create the []*RPCRequest array yourself, but it is not recommended and you should notice the following:
          	// - field Params is sent as provided, so Params: 2 forms an invalid json (correct would be Params: []int{2})
          	// - you can use the helper function Params(1, 2, 3) to use the same format as in Call()
          	// - field JSONRPC is overwritten and set to value: "2.0"
          	// - field ID is overwritten and set incrementally and maps to the array position (e.g. requests[5].ID == 5)
          	//
          	//
          	// Returns RPCResponses that is of type []*RPCResponse
          	// - note that a list of RPCResponses can be received unordered so it can happen that: responses[i] != responses[i].ID
          	// - RPCPersponses is enriched with helper functions e.g.: responses.HasError() returns  true if one of the responses holds an RPCError
          	CallBatch(requests RPCRequests) (RPCResponses, error)
          
          	// CallBatchRaw invokes a list of RPCRequests in a single batch request.
          	// It sends the RPCRequests parameter is it passed (no magic, no id autoincrement).
          	//
          	// Consider to use CallBatch() instead except you have some good reason not to.
          	//
          	// CallBatchRaw(RPCRequests{
          	//   &RPCRequest{
          	//     ID: 123,            // this won't be replaced in CallBatchRaw
          	//     JSONRPC: "wrong",   // this won't be replaced in CallBatchRaw
          	//     Method: "myMethod1",
          	//     Params: []int{1},   // there is no magic, be sure to only use array or object
          	//   },
          	//   &RPCRequest{
          	//     ID: 612,
          	//     JSONRPC: "2.0",
          	//     Method: "myMethod2",
          	//     Params: Params("Alex", 35, true), // you can use helper function Params() (see doc)
          	//   },
          	// })
          	//
          	// Returns RPCResponses that is of type []*RPCResponse
          	// - note that a list of RPCResponses can be received unordered
          	// - the id's must be mapped against the id's you provided
          	// - RPCPersponses is enriched with helper functions e.g.: responses.HasError() returns  true if one of the responses holds an RPCError
          	CallBatchRaw(requests RPCRequests) (RPCResponses, error)
          }

            RPCClient sends JSON-RPC requests over HTTP to the provided JSON-RPC backend.

            RPCClient is created using the factory function NewClient().

            func NewClient

            func NewClient(endpoint string) RPCClient

              NewClient returns a new RPCClient instance with default configuration.

              endpoint: JSON-RPC service URL to which JSON-RPC requests are sent.

              func NewClientWithOpts

              func NewClientWithOpts(endpoint string, opts *RPCClientOpts) RPCClient

                NewClientWithOpts returns a new RPCClient instance with custom configuration.

                endpoint: JSON-RPC service URL to which JSON-RPC requests are sent.

                opts: RPCClientOpts provide custom configuration

                type RPCClientOpts

                type RPCClientOpts struct {
                	HTTPClient    *http.Client
                	CustomHeaders map[string]string
                }

                  RPCClientOpts can be provided to NewClientWithOpts() to change configuration of RPCClient.

                  HTTPClient: provide a custom http.Client (e.g. to set a proxy, or tls options)

                  CustomHeaders: provide custom headers, e.g. to set BasicAuth

                  type RPCError

                  type RPCError struct {
                  	Code    int         `json:"code"`
                  	Message string      `json:"message"`
                  	Data    interface{} `json:"data,omitempty"`
                  }

                    RPCError represents a JSON-RPC error object if an RPC error occurred.

                    Code: holds the error code

                    Message: holds a short error message

                    Data: holds additional error data, may be nil

                    See: http://www.jsonrpc.org/specification#error_object

                    func (*RPCError) Error

                    func (e *RPCError) Error() string

                      Error function is provided to be used as error object.

                      type RPCRequest

                      type RPCRequest struct {
                      	Method  string      `json:"method"`
                      	Params  interface{} `json:"params,omitempty"`
                      	ID      int         `json:"id"`
                      	JSONRPC string      `json:"jsonrpc"`
                      }

                        RPCRequest represents a JSON-RPC request object.

                        Method: string containing the method to be invoked

                        Params: can be nil. if not must be an json array or object

                        ID: may always set to 1 for single requests. Should be unique for every request in one batch request.

                        JSONRPC: must always be set to "2.0" for JSON-RPC version 2.0

                        See: http://www.jsonrpc.org/specification#request_object

                        Most of the time you shouldn't create the RPCRequest object yourself. The following functions do that for you: Call(), CallFor(), NewRequest()

                        If you want to create it yourself (e.g. in batch or CallRaw()), consider using Params(). Params() is a helper function that uses the same parameter syntax as Call().

                        e.g. to manually create an RPCRequest object: request := &RPCRequest{

                        Method: "myMethod",
                        Params: Params("Alex", 35, true),
                        

                        }

                        If you know what you are doing you can omit the Params() call to avoid some reflection but potentially create incorrect rpc requests: request := &RPCRequest{

                        Method: "myMethod",
                        Params: 2, <-- invalid since a single primitive value must be wrapped in an array --> no magic without Params()
                        

                        }

                        correct: request := &RPCRequest{

                        Method: "myMethod",
                        Params: []int{2}, <-- invalid since a single primitive value must be wrapped in an array
                        

                        }

                        func NewRequest

                        func NewRequest(method string, params ...interface{}) *RPCRequest

                          NewRequest returns a new RPCRequest that can be created using the same convenient parameter syntax as Call()

                          e.g. NewRequest("myMethod", "Alex", 35, true)

                          type RPCRequests

                          type RPCRequests []*RPCRequest

                            RPCRequests is of type []*RPCRequest. This type is used to provide helper functions on the request list

                            type RPCResponse

                            type RPCResponse struct {
                            	JSONRPC string      `json:"jsonrpc"`
                            	Result  interface{} `json:"result,omitempty"`
                            	Error   *RPCError   `json:"error,omitempty"`
                            	ID      int         `json:"id"`
                            }

                              RPCResponse represents a JSON-RPC response object.

                              Result: holds the result of the rpc call if no error occurred, nil otherwise. can be nil even on success.

                              Error: holds an RPCError object if an error occurred. must be nil on success.

                              ID: may always be 0 for single requests. is unique for each request in a batch call (see CallBatch())

                              JSONRPC: must always be set to "2.0" for JSON-RPC version 2.0

                              See: http://www.jsonrpc.org/specification#response_object

                              func (*RPCResponse) GetBool

                              func (RPCResponse *RPCResponse) GetBool() (bool, error)

                                GetBool converts the rpc response to a bool and returns it.

                                If result was not a bool an error is returned.

                                func (*RPCResponse) GetFloat

                                func (RPCResponse *RPCResponse) GetFloat() (float64, error)

                                  GetFloat converts the rpc response to float64 and returns it.

                                  If result was not an float64 an error is returned.

                                  func (*RPCResponse) GetInt

                                  func (RPCResponse *RPCResponse) GetInt() (int64, error)

                                    GetInt converts the rpc response to an int64 and returns it.

                                    If result was not an integer an error is returned.

                                    func (*RPCResponse) GetObject

                                    func (RPCResponse *RPCResponse) GetObject(toType interface{}) error

                                      GetObject converts the rpc response to an arbitrary type.

                                      The function works as you would expect it from json.Unmarshal()

                                      func (*RPCResponse) GetString

                                      func (RPCResponse *RPCResponse) GetString() (string, error)

                                        GetString converts the rpc response to a string and returns it.

                                        If result was not a string an error is returned.

                                        type RPCResponses

                                        type RPCResponses []*RPCResponse

                                          RPCResponses is of type []*RPCResponse. This type is used to provide helper functions on the result list

                                          func (RPCResponses) AsMap

                                          func (res RPCResponses) AsMap() map[int]*RPCResponse

                                            AsMap returns the responses as map with response id as key.

                                            func (RPCResponses) GetByID

                                            func (res RPCResponses) GetByID(id int) *RPCResponse

                                              GetByID returns the response object of the given id, nil if it does not exist.

                                              func (RPCResponses) HasError

                                              func (res RPCResponses) HasError() bool

                                                HasError returns true if one of the response objects has Error field != nil

                                                Source Files