jsonrpc2

package module
v15.0.0-...-43d2d97 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2021 License: MIT Imports: 12 Imported by: 12

README

github.com/AccumulateNetwork/jsonrpc2/v15

Package jsonrpc2 is a complete and strictly conforming implementation of the JSON-RPC 2.0 protocol for both clients and servers.

The full specification can be found at https://www.jsonrpc.org.

Clients

The simplest way to make a JSON-RPC 2.0 request is to use the provided Client.Request.

     var c jsonrpc2.Client
     params := []float64{1, 2, 3}
     var result int
     err := c.Request(nil, "http://localhost:8080", "sum", params, &result)
     if _, ok := err.(jsonrpc2.Error); ok {
     	// received Error Request
     }
     if err != nil {
     	// some JSON marshaling or network error
     }
     fmt.Printf("The sum of %v is %v.\n", params, result)

For clients that do not wish to use the provided Client, the Request and Response types can be used directly.

     req, _ := json.Marshal(jsonrpc2.Request{Method: "subtract",
       	Params: []int{5, 1},
       	ID:     0,
       })
       httpRes, _ := http.Post("www.example.com", "application/json",
       	bytes.NewReader(req))
       resBytes, _ := ioutil.ReadAll(httpRes.Body)
       res := jsonrpc2.Response{Result: &MyCustomResultType{}, ID: new(int)}
       json.Unmarshal(respBytes, &res)

Servers

Servers define their own MethodFuncs and associate them with a name in a MethodMap that is passed to HTTPRequestHandler() to return a corresponding http.HandlerFunc. See HTTPRequestHandler for more details.

     func getUser(ctx context.Context, params json.RawMessage) interface{} {
     	var u User
     	if err := json.Unmarshal(params, &u); err != nil {
     		return jsonrpc2.InvalidParams(err)
     	}
     	conn, err := mydbpkg.GetDBConn()
     	if err != nil {
     		// The handler will recover, print debug info if enabled, and
     		// return an Internal Error to the client.
     		panic(err)
     	}
     	if err := u.Select(conn); err != nil {
     		return jsonrpc2.NewError(-30000, "user not found", u.ID)
     	}
     	return u
     }

     func StartServer() {
     	methods := jsonrpc2.MethodMap{"version": versionMethod}
     	http.ListenAndServe(":8080", jsonrpc2.HTTPRequestHandler(methods))
     }

Documentation

Overview

Package jsonrpc2 is a complete and strictly conforming implementation of the JSON-RPC 2.0 protocol for both clients and servers.

The full specification can be found at https://www.jsonrpc.org.

Clients

The simplest way to make a JSON-RPC 2.0 request is to use the provided Client.Request.

var c jsonrpc2.Client
params := []float64{1, 2, 3}
var result int
err := c.Request(nil, "http://localhost:8080", "sum", params, &result)
if _, ok := err.(jsonrpc2.Error); ok {
	// received Error Request
}
if err != nil {
	// some JSON marshaling or network error
}
fmt.Printf("The sum of %v is %v.\n", params, result)

For clients that do not wish to use the provided Client, the Request and Response types can be used directly.

     req, _ := json.Marshal(jsonrpc2.Request{Method: "subtract",
		Params: []int{5, 1},
		ID:     0,
	})
	httpRes, _ := http.Post("www.example.com", "application/json",
		bytes.NewReader(req))
	resBytes, _ := ioutil.ReadAll(httpRes.Body)
	res := jsonrpc2.Response{Result: &MyCustomResultType{}, ID: new(int)}
	json.Unmarshal(respBytes, &res)

Servers

Servers define their own MethodFuncs and associate them with a name in a MethodMap that is passed to HTTPRequestHandler() to return a corresponding http.HandlerFunc. See HTTPRequestHandler for more details.

func getUser(ctx context.Context, params json.RawMessage) interface{} {
	var u User
	if err := json.Unmarshal(params, &u); err != nil {
		return jsonrpc2.InvalidParams(err)
	}
	conn, err := mydbpkg.GetDBConn()
	if err != nil {
		// The handler will recover, print debug info if enabled, and
		// return an Internal Error to the client.
		panic(err)
	}
	if err := u.Select(conn); err != nil {
		return jsonrpc2.NewError(-30000, "user not found", u.ID)
	}
	return u
}

func StartServer() {
	methods := jsonrpc2.MethodMap{"version": versionMethod}
	http.ListenAndServe(":8080", jsonrpc2.HTTPRequestHandler(methods,
                log.New(os.Stderr, "", 0)))
}
Example

This example makes all of the calls from the examples in the JSON-RPC 2.0 specification and prints them in a similar format.

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/AccumulateNetwork/jsonrpc2/v15"
)

var endpoint = "http://localhost:18888"

// Functions for making requests and printing the Requests and Responses.
func post(b []byte) []byte {
	httpResp, _ := http.Post(endpoint, "", bytes.NewReader(b))
	respBytes, _ := ioutil.ReadAll(httpResp.Body)
	return respBytes
}
func postNewRequest(method string, id, params interface{}) {
	postRequest(jsonrpc2.Request{Method: method, ID: id, Params: params})
}
func postRequest(request interface{}) {
	fmt.Println(request)
	reqBytes, _ := json.Marshal(request)
	respBytes := post(reqBytes)
	parseResponse(respBytes)
}
func parseResponse(respBytes []byte) {
	var response interface{}
	if len(respBytes) == 0 {
		return
	} else if string(respBytes[0]) == "[" {
		response = &jsonrpc2.BatchResponse{}
	} else {
		response = &jsonrpc2.Response{}
	}
	if err := json.Unmarshal(respBytes, response); err != nil {
		fmt.Println(string(respBytes), err)
		return
	}
	fmt.Println(response)
	fmt.Println()
}
func postBytes(req string) {
	fmt.Println("-->", req)
	respBytes := post([]byte(req))
	parseResponse(respBytes)
}

// The RPC methods called in the JSON-RPC 2.0 specification examples.
func subtract(_ context.Context, params json.RawMessage) interface{} {
	// Parse either a params array of numbers or named numbers params.
	var a []float64
	if err := json.Unmarshal(params, &a); err == nil {
		if len(a) != 2 {
			return jsonrpc2.ErrorInvalidParams("Invalid number of array params")
		}
		return a[0] - a[1]
	}
	var p struct {
		Subtrahend *float64
		Minuend    *float64
	}
	if err := json.Unmarshal(params, &p); err != nil ||
		p.Subtrahend == nil || p.Minuend == nil {
		return jsonrpc2.ErrorInvalidParams(`Required fields "subtrahend" and ` +
			`"minuend" must be valid numbers.`)
	}
	return *p.Minuend - *p.Subtrahend
}
func sum(_ context.Context, params json.RawMessage) interface{} {
	var p []float64
	if err := json.Unmarshal(params, &p); err != nil {
		return jsonrpc2.ErrorInvalidParams(err)
	}
	sum := float64(0)
	for _, x := range p {
		sum += x
	}
	return sum
}
func notifyHello(_ context.Context, _ json.RawMessage) interface{} {
	return ""
}
func getData(_ context.Context, _ json.RawMessage) interface{} {
	return []interface{}{"hello", 5}
}

// This example makes all of the calls from the examples in the JSON-RPC 2.0
// specification and prints them in a similar format.
func main() {
	// Start the server.
	go func() {
		// Register RPC methods.
		methods := jsonrpc2.MethodMap{
			"subtract":     subtract,
			"sum":          sum,
			"notify_hello": notifyHello,
			"get_data":     getData,
		}
		jsonrpc2.DebugMethodFunc = true
		handler := jsonrpc2.HTTPRequestHandler(methods, log.New(os.Stdout, "", 0))
		http.ListenAndServe(":18888", handler)
	}()

	// Make requests.
	fmt.Println("Syntax:")
	fmt.Println("--> data sent to Server")
	fmt.Println("<-- data sent to Client")
	fmt.Println("")

	fmt.Println("rpc call with positional parameters:")
	postNewRequest("subtract", 1, []int{42, 23})
	postNewRequest("subtract", 2, []int{23, 42})

	fmt.Println("rpc call with named parameters:")
	postNewRequest("subtract", 3, map[string]int{"subtrahend": 23, "minuend": 42})
	postNewRequest("subtract", 4, map[string]int{"minuend": 42, "subtrahend": 23})

	fmt.Println("a Notification:")
	postNewRequest("update", nil, []int{1, 2, 3, 4, 5})
	postNewRequest("foobar", nil, nil)
	fmt.Println()

	fmt.Println("rpc call of non-existent method:")
	postNewRequest("foobar", "1", nil)

	fmt.Println("rpc call with invalid JSON:")
	postBytes(`{"jsonrpc":"2.0","method":"foobar,"params":"bar","baz]`)

	fmt.Println("rpc call with invalid Request object:")
	postBytes(`{"jsonrpc":"2.0","method":1,"params":"bar"}`)

	fmt.Println("rpc call Batch, invalid JSON:")
	postBytes(
		`[
  {"jsonrpc":"2.0","method":"sum","params":[1,2,4],"id":"1"},
  {"jsonrpc":"2.0","method"
]`)

	fmt.Println("rpc call with an empty Array:")
	postBytes(`[]`)

	fmt.Println("rpc call with an invalid Batch (but not empty):")
	postBytes(`[1]`)

	fmt.Println("rpc call with invalid Batch:")
	postBytes(`[1,2,3]`)

	fmt.Println("rpc call Batch:")
	postBytes(`[
  {"jsonrpc":"2.0","method":"sum","params":[1,2,4],"id":"1"},
  {"jsonrpc":"2.0","method":"notify_hello","params":[7]},
  {"jsonrpc":"2.0","method":"subtract","params":[42,23],"id":"2"},
  {"foo":"boo"},
  {"jsonrpc":"2.0","method":"foo.get","params":{"name":"myself"},"id":"5"},
  {"jsonrpc":"2.0","method":"get_data","id":"9"}
]`)
	fmt.Println("rpc call Batch (all notifications):")
	postRequest(jsonrpc2.BatchRequest{
		jsonrpc2.Request{Method: "notify_sum", ID: nil, Params: []int{1, 2, 4}},
		jsonrpc2.Request{Method: "notify_hello", ID: nil, Params: []int{7}},
	})
	fmt.Println("<-- //Nothing is returned for all notification batches")

}
Output:

Syntax:
--> data sent to Server
<-- data sent to Client

rpc call with positional parameters:
--> {"jsonrpc":"2.0","method":"subtract","params":[42,23],"id":1}
<-- {"jsonrpc":"2.0","result":19,"id":1}

--> {"jsonrpc":"2.0","method":"subtract","params":[23,42],"id":2}
<-- {"jsonrpc":"2.0","result":-19,"id":2}

rpc call with named parameters:
--> {"jsonrpc":"2.0","method":"subtract","params":{"minuend":42,"subtrahend":23},"id":3}
<-- {"jsonrpc":"2.0","result":19,"id":3}

--> {"jsonrpc":"2.0","method":"subtract","params":{"minuend":42,"subtrahend":23},"id":4}
<-- {"jsonrpc":"2.0","result":19,"id":4}

a Notification:
--> {"jsonrpc":"2.0","method":"update","params":[1,2,3,4,5]}
--> {"jsonrpc":"2.0","method":"foobar"}

rpc call of non-existent method:
--> {"jsonrpc":"2.0","method":"foobar","id":"1"}
<-- {"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found","data":"foobar"},"id":"1"}

rpc call with invalid JSON:
--> {"jsonrpc":"2.0","method":"foobar,"params":"bar","baz]
<-- {"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}

rpc call with invalid Request object:
--> {"jsonrpc":"2.0","method":1,"params":"bar"}
<-- {"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request","data":"json: cannot unmarshal number into Go struct field jRequest.method of type string"},"id":null}

rpc call Batch, invalid JSON:
--> [
  {"jsonrpc":"2.0","method":"sum","params":[1,2,4],"id":"1"},
  {"jsonrpc":"2.0","method"
]
<-- {"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}

rpc call with an empty Array:
--> []
<-- {"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request","data":"empty batch request"},"id":null}

rpc call with an invalid Batch (but not empty):
--> [1]
<-- [
  {"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request","data":"json: cannot unmarshal number into Go value of type jsonrpc2.jRequest"},"id":null}
]

rpc call with invalid Batch:
--> [1,2,3]
<-- [
  {"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request","data":"json: cannot unmarshal number into Go value of type jsonrpc2.jRequest"},"id":null},
  {"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request","data":"json: cannot unmarshal number into Go value of type jsonrpc2.jRequest"},"id":null},
  {"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request","data":"json: cannot unmarshal number into Go value of type jsonrpc2.jRequest"},"id":null}
]

rpc call Batch:
--> [
  {"jsonrpc":"2.0","method":"sum","params":[1,2,4],"id":"1"},
  {"jsonrpc":"2.0","method":"notify_hello","params":[7]},
  {"jsonrpc":"2.0","method":"subtract","params":[42,23],"id":"2"},
  {"foo":"boo"},
  {"jsonrpc":"2.0","method":"foo.get","params":{"name":"myself"},"id":"5"},
  {"jsonrpc":"2.0","method":"get_data","id":"9"}
]
<-- [
  {"jsonrpc":"2.0","result":7,"id":"1"},
  {"jsonrpc":"2.0","result":19,"id":"2"},
  {"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request","data":"json: unknown field \"foo\""},"id":null},
  {"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found","data":"foo.get"},"id":"5"},
  {"jsonrpc":"2.0","result":["hello",5],"id":"9"}
]

rpc call Batch (all notifications):
--> [
  {"jsonrpc":"2.0","method":"notify_sum","params":[1,2,4]},
  {"jsonrpc":"2.0","method":"notify_hello","params":[7]}
]
<-- //Nothing is returned for all notification batches

Index

Examples

Constants

View Source
const (
	// ErrorCodeMinReserved is the minimum reserved error code. Method
	// defined errors may be less than this value.
	ErrorCodeMinReserved ErrorCode = -32768

	// ErrorCodeParse means the received data was not valid JSON.
	ErrorCodeParse    ErrorCode = -32700
	ErrorMessageParse           = "Parse error"

	// ErrorCodeInvalidRequest means the received valid JSON is not a valid
	// Request object.
	ErrorCodeInvalidRequest    ErrorCode = -32600
	ErrorMessageInvalidRequest           = "Invalid Request"

	// ErrorCodeMethodNotFound means the requested method is not defined
	// for the HTTPRequestHandler.
	ErrorCodeMethodNotFound    ErrorCode = -32601
	ErrorMessageMethodNotFound           = "Method not found"

	// ErrorCodeInvalidParams means a method is called with invalid method
	// parameter(s).
	//
	// MethodFuncs are responsible for detecting and returning this error.
	ErrorCodeInvalidParams    ErrorCode = -32602
	ErrorMessageInvalidParams           = "Invalid params"

	// ErrorCodeInternal means an internal error occurred such as a
	// MethodFunc panic.
	ErrorCodeInternal    ErrorCode = -32603
	ErrorMessageInternal           = "Internal error"

	// ErrorCodeMaxReserved is the maximum reserved error code. Method
	// defined errors may be greater than this value.
	ErrorCodeMaxReserved ErrorCode = -32000
)

Official JSON-RPC 2.0 Spec Error Codes and Messages

Variables

View Source
var DebugMethodFunc = false

DebugMethodFunc controls whether additional debug information is printed to stdout in the event of an InternalError when a MethodFunc is called.

This can be helpful when troubleshooting panics or Internal Errors from a MethodFunc.

Functions

func HTTPRequestHandler

func HTTPRequestHandler(methods MethodMap, lgr Logger) http.HandlerFunc

HTTPRequestHandler returns an http.HandlerFunc for the given methods.

The returned http.HandlerFunc efficiently handles any conforming single or batch requests or notifications, accurately catches all defined protocol errors, calls the appropriate MethodFuncs, recovers from any panics or invalid return values, and returns an Internal Error or Response with the correct ID, if not a Notification.

See MethodFunc for more details.

It is not safe to modify methods while the returned http.HandlerFunc is in use.

This will panic if a method name beginning with "rpc." is used. See MethodMap for more details.

The handler will use lgr to log any errors and debug information, if DebugMethodFunc is true. If lgr is nil, the default Logger from the log package is used.

Types

type BatchRequest

type BatchRequest []Request

BatchRequest is a type that implements fmt.Stringer for a slice of Requests.

func (BatchRequest) String

func (br BatchRequest) String() string

String returns br as a JSON array prefixed with "--> " to indicate an outgoing BatchRequest and with newlines separating the elements of br.

type BatchResponse

type BatchResponse []Response

BatchResponse is a type that implements fmt.Stringer for a slice of Responses.

func (BatchResponse) String

func (br BatchResponse) String() string

String returns br as a JSON array prefixed with "<-- " to indicate an incoming BatchResponse and with newlines separating the elements of br.

type Client

type Client struct {
	http.Client
	DebugRequest bool
	Log          Logger

	BasicAuth bool
	User      string
	Password  string
	Header    http.Header
}

Client embeds http.Client and provides a convenient way to make JSON-RPC 2.0 requests.

func (*Client) Request

func (c *Client) Request(ctx context.Context, url, method string,
	params, result interface{}) error

Request uses c to make a JSON-RPC 2.0 Request to url with the given method and params, and then parses the Response using the provided result, which should be a pointer so that it may be populated.

If ctx is not nil, it is added to the http.Request.

If the http.Response is received without error, but cannot be parsed into a Response, then an ErrorUnexpectedHTTPResponse is returned containing the Unmarshaling error, the raw bytes of the http.Response.Body, and the http.Response.

If the Response.HasError() is true, then the Error is returned.

Other potential errors can result from json.Marshal and params, http.NewRequest and url, or network errors from c.Do.

A pseudorandom uint between 1 and 5000 is used for the Request.ID.

The "Content-Type":"application/json" header is added to the http.Request, and then headers in c.Header are added, which may override the "Content-Type".

If c.BasicAuth is true then http.Request.SetBasicAuth(c.User, c.Password) is be called.

If c.DebugRequest is true then the Request and Response are printed using c.Log. If c.Log == nil, then c.Log = log.New(os.Stderr, "", 0).

type Error

type Error struct {
	// Code is a number that indicates the error type that occurred.
	Code ErrorCode `json:"code"`

	// Message is a short description of the error. The message SHOULD be
	// limited to a concise single sentence.
	Message string `json:"message"`

	// Data is a Primitive or Structured value that contains additional
	// information about the error. This may be omitted. The value of this
	// member is defined by the Server (e.g. detailed error information,
	// nested errors etc.).
	Data interface{} `json:"data,omitempty"`
}

Error represents a JSON-RPC 2.0 Error object, which is used in the Response object. MethodFuncs may return an Error or *Error to return an Error Response to the client.

func ErrorInvalidParams

func ErrorInvalidParams(data interface{}) Error

ErrorInvalidParams returns

NewError(ErrorCodeInvalidParams, ErrorMessageInvalidParams, data)

MethodFuncs are responsible for detecting invalid parameters and returning this error.

func NewError

func NewError(code ErrorCode, msg string, data interface{}) Error

NewError returns an Error with code, msg, and data.

The data must not cause an error when passed to json.Marshal, else any MethodFunc returning it will return an Internal Error to clients instead.

If data is type error, then the Error() string is used instead, since otherwise the error may not json.Marshal properly.

func (Error) Error

func (e Error) Error() string

Error implements the error interface.

func (Error) IsZero

func (e Error) IsZero() bool

IsZero reports whether e is zero valued.

type ErrorCode

type ErrorCode int

ErrorCode indicates the Error type that occurred.

The error codes from and including -32768 to -32000 are reserved for pre-defined errors. Any code within this range, but not defined explicitly below is reserved for future use.

See ErrorCodeMinReserved.

func (ErrorCode) IsReserved

func (c ErrorCode) IsReserved() bool

IsReserved returns true if c is within the reserved error code range:

[LowestReservedErrorCode, HighestReservedErrorCode]

func (ErrorCode) String

func (c ErrorCode) String() string

type ErrorUnexpectedHTTPResponse

type ErrorUnexpectedHTTPResponse struct {
	UnmarshlingErr error
	Body           []byte
	*http.Response
}

ErrorUnexpectedHTTPResponse wraps errors that occur during unmarshling of the http.Response.Body into a Response, along with the full bytes of the http.Response.Body and the http.Response itself.

func (ErrorUnexpectedHTTPResponse) Error

func (err ErrorUnexpectedHTTPResponse) Error() string

Error returns err.UnmarshalingErr.Error().

func (*ErrorUnexpectedHTTPResponse) Unwrap

func (err *ErrorUnexpectedHTTPResponse) Unwrap() error

Unwrap return err.UnmarshalingErr.

type Logger

type Logger interface {
	Println(...interface{})
	Printf(string, ...interface{})
}

Logger allows custom log types to be used with the Client when Client.DebugRequest is true.

type MethodFunc

type MethodFunc func(ctx context.Context, params json.RawMessage) interface{}

MethodFunc is the function signature used for RPC methods.

MethodFuncs are invoked by the HTTPRequestHandler when a valid Request is received. MethodFuncs do not need to concern themselves with the details of JSON-RPC 2.0 outside of the "params" field, as all parsing and validation is handled by the handler.

The handler will call a MethodFunc with ctx set to the corresponding http.Request.Context() and params set to the JSON data from the "params" field of the Request. If "params" was omitted or null, params will be nil. Otherwise, params is guaranteed to be valid JSON that represents a JSON Object or Array.

A MethodFunc is responsible for application specific parsing of params. A MethodFunc should return an ErrorInvalidParams if there is any issue parsing expected parameters.

To return a success Response to the client a MethodFunc must return a non-error value, that will not cause an error when passed to json.Marshal, to be used as the Response.Result. Any marshaling error will cause a panic and an Internal Error will be returned to the client.

To return an Error Response to the client, a MethodFunc must return a valid Error. A valid Error must use ErrorCodeInvalidParams or any ErrorCode outside of the reserved range, and the Error.Data must not cause an error when passed to json.Marshal. If the Error is not valid, a panic will occur and an Internal Error will be returned to the client.

If a MethodFunc panics or returns any other error, an Internal Error is returned to the client. If the returned error is anything other than context.Canceled or context.DeadlineExceeded, a panic will occur.

For additional debug output from a MethodFunc regarding the cause of an Internal Error, set DebugMethodFunc to true. Information about the method call and a stack trace will be printed on panics.

type MethodMap

type MethodMap map[string]MethodFunc

MethodMap associates method names with MethodFuncs and is passed to HTTPRequestHandler to generate a corresponding http.HandlerFunc.

Method names that begin with the word rpc followed by a period character (U+002E or ASCII 46) are reserved for rpc-internal methods and extensions and MUST NOT be used for anything else. If such a method name is detected this will panic. No such internal rpc methods are yet defined in this implementation.

type Request

type Request struct {
	// Method is a string containing the name of the method to be invoked.
	Method string `json:"method"`

	// Params is a structured value that holds the parameter values to be
	// used during the invocation of the method.
	//
	// This member MAY be omitted.
	Params interface{} `json:"params,omitempty"`

	// ID is an identifier established by the Client that MUST contain a
	// String, Number, or NULL value if included.
	//
	// If it is not included it is assumed to be a notification. The value
	// SHOULD normally not be Null and Numbers SHOULD NOT contain
	// fractional parts.
	ID interface{} `json:"id,omitempty"`
}

Request represents a JSON-RPC 2.0 Request or Notification object.

This type is not needed to use the Client or to write MethodFuncs for the HTTPRequestHandler.

Request is intended to be used externally to MarshalJSON for custom clients, and internally to UnmarshalJSON for the HTTPRequestHandler.

To make a Request, you must populate ID. If ID is empty, the Request is treated as a Notification and does not receive a Response. See MarshalJSON for more details.

func (Request) MarshalJSON

func (r Request) MarshalJSON() ([]byte, error)

MarshalJSON attempts to marshal r into a valid JSON-RPC 2.0 Request or Notification object.

If r.ID is nil, then the returned data represents a Notification.

If r.ID is not nil, then the returned data represents a Request. Also, an `invalid "id": ...` error is returned if the r.ID does not marshal into a valid JSON number, string, or null. Although technically permitted, it is not recommended to use json.RawMessage("null") as an ID, as this is used by Responses when there is an error parsing "id".

If r.Params is not nil, then an `invalid "params": ...` error is returned if it does not marshal into a valid JSON object, array, or null.

An empty Method, though not recommended, is technically valid and does not cause an error.

func (Request) String

func (r Request) String() string

String returns r as a JSON object prefixed with "--> " to indicate an outgoing Request.

If r.MarshalJSON returns an error then the error string is returned with some context.

func (*Request) UnmarshalJSON

func (r *Request) UnmarshalJSON(data []byte) error

UnmarshalJSON attempts to unmarshal a JSON-RPC 2.0 Request or Notification into r and then validates it.

To allow for precise JSON type validation and to avoid unneeded unmarshaling by the HTTPRequestHandler, "id" and "params" are both unmarshaled into json.RawMessage. After a successful call, r.ID and r.Params are set to a json.RawMessage that is either nil or contains the raw JSON for the respective field. So, if no error is returned, this is guaranteed to not panic:

id, params := r.ID.(json.RawMessage), r.Params.(json.RawMessage)

If "id" is omitted, then r.ID is set to json.RawMessage(nil). If "id" is null, then r.ID is set to json.RawMessage("null").

If "params" is null or omitted, then r.Params is set to json.RawMessage(nil).

If any fields are unknown, an error is returned.

If the "jsonrpc" field is not set to the string "2.0", an `invalid "jsonrpc" version: ...` error is be returned.

If the "method" field is omitted or null, a `missing "method"` error is returned. An explicitly empty "method" string does not cause an error.

If the "id" value is not a JSON number, string, or null, an `invalid "id": ...` error is returned.

If the "params" value is not a JSON array, object, or null, an `invalid "params": ...` error is returned.

type Response

type Response struct {
	// Result is REQUIRED on success. This member MUST NOT exist if there
	// was an error invoking the method. The value of this member is
	// determined by the method invoked on the Server.
	Result interface{} `json:"result,omitempty"`

	// Error is REQUIRED on error. This member MUST NOT exist if there was
	// no error triggered during invocation. The value for this member MUST
	// be an Object as defined in section 5.1.
	//
	// See Response.HasError.
	Error Error `json:"error,omitempty"`

	// ID is an identifier established by the client that MUST contain a
	// String, Number, or NULL value if included.
	//
	// Since a Request without an ID is not responded to, this member is
	// REQUIRED. It MUST be the same as the value of the id member in the
	// Request Object. If there was an error in detecting the id in the
	// Request Object (e.g. Parse error/Invalid Request), it MUST be Null.
	ID interface{} `json:"id"`
}

Response represents a JSON-RPC 2.0 Response object.

This type is not needed to use the Client or to write MethodFuncs for the HTTPRequestHandler.

Response is intended to be used externally to UnmarshalJSON for custom clients, and internally to MarshalJSON for the provided HTTPRequestHandler.

To receive a Response, it is recommended to set Result to a pointer to a value that the "result" can be unmarshaled into, if known prior to unmarshaling. Similarly, it is recommended to set ID to a pointer to a value that the "id" can be unmarshaled into, which should be the same type as the Request ID.

func (Response) HasError

func (r Response) HasError() bool

HasError returns true is r.Error has any non-zero values.

func (Response) MarshalJSON

func (r Response) MarshalJSON() ([]byte, error)

MarshalJSON attempts to marshal r into a valid JSON-RPC 2.0 Response.

If r.HasError(), then "result" is omitted from the JSON, and if r.ID is nil, it is set to json.RawMessage("null"). An error is only returned if r.Error.Data or r.ID is not marshalable.

If !r.HasError(), then if r.ID is nil, an error is returned. If r.Result is nil, it is populated with json.RawMessage("null").

Also, an error is returned if r.Result or r.ID is not marshalable.

func (Response) String

func (r Response) String() string

String returns r as a JSON object prefixed with "<-- " to indicate an incoming Response.

If r.MarshalJSON returns an error then the error string is returned with some context.

func (*Response) UnmarshalJSON

func (r *Response) UnmarshalJSON(data []byte) error

UnmarshalJSON attempts to unmarshal a JSON-RPC 2.0 Response into r and then validates it.

If any fields are unknown other than the application specific fields in the "result" object, an error is returned.

If "error" and "result" are both present or not null, a `contains both ...` error is returned.

If the "jsonrpc" field is not set to the string "2.0", an `invalid "jsonrpc" version: ...` error is returned.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL