jsonrpc

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Apr 11, 2020 License: MIT Imports: 9 Imported by: 0

README

jsonrpc

GoDoc Go Go Report Card

Standards-compliant JSON-RPC 2.0 over HTTP for Go.

How to use

Create a new Handler and register methods to it. A method is any Go function with certain restrictions:

  • The method may contain a context.Context as its first argument.
  • The method must only have JSON-serializable arguments otherwise.
  • The method may return a JSON-serializable object as its first return value.
  • The method may return an error as its last return value.
  • The method must not have any other return values.

The JSON-RPC 2.0 handler only responds to POST requests.

h := jsonrpc.NewHandler()
h.RegisterMethod("echo", func (in string) string {
	return in
})
http.ListenAndServe(":8080", h)

Context

A method has access to the context.Context from the http.Request. A common use case is to use middleware to attach security credentials to the context, and then extract those credentials in the method to validate the user's authorization or return user-specific data.

h.RegisterMethod("secure", func(ctx context.Context) (string, error) {
	_, ok := ctx.Value("secure-cookie")
	if !ok {
		return "", fmt.Errorf("Invalid credentials.")
	}
	return "Top secret data", nil
})

JSON-RPC Errors

If you want to provide a JSON-RPC 2.0 error, use the Error struct. This lets you provide a custom error code and custom data.

h.RegisterMethod("bad", func (data json.RawMessage) error {
	return &jsonrpc.Error{
		Code: 101,
		Message: "This endpoint is bad.",
		Data: data,
	}
})

Multiple Registration

For convenience, you may register all methods on a value at once using Register.

a := SomeNewApi()
h.Register(a)

Motivation

When used this way, JSON-RPC 2.0 endpoints become self-documenting. They correspond exactly to their Go functions. They are testable.

This also allows almost any Go function to be used (unlike the built-in rpc/jsonrpc package in the Go standard library).

Documentation

Overview

Package jsonrpc implements the JSON-RPC 2.0 specification over HTTP.

Regular functions can be registered to a Handler and then called using standard JSON-RPC 2.0 semantics. The only limitations on functions are as follows:

  • the first parameter may be a context.Context
  • the remaining parameters must be able to unmarshal from JSON
  • return values must be (optionally) a value and (optionally) an error
  • if there is a return value, it must be able to marshal as JSON

Here is a simple example of a JSON-RPC 2.0 command that echos its input:

h := jsonrpc.NewHandler()
h.RegisterMethod("echo", func (in string) string { return in })
http.ListenAndServe(":8080", h)

You would call this over HTTP with standard JSON-RPC 2.0 semantics:

=> {"jsonrpc": "2.0", "id": 1, "method": "echo", "params": ["Hello world!"]}
<= {"jsonrpc": "2.0", "id": 1, "result": "Hello world!"}

As a convenience, structs may also be registered to a Handler. In this case, each method of the struct is registered using the method "Type.Method". For example:

type Echo struct{}

func (Echo) Echo(s string) string {
	return s
}

func main() {
	e := &Echo{}
	h := jsonrpc.NewHandler()
	h.Register(e)
	http.ListenAndServe(":8080", h)
}

Then you would call this over HTTP as follows:

=> {"jsonrpc": "2.0", "id": 1, "method": "Echo.Echo", "params": ["Hello world!"]}
<= {"jsonrpc": "2.0", "id": 1, "result": "Hello world!"}

As a further convenience, you may pass in one or more structs into the NewHandler constructor. For example:

http.ListenAndServe(":8080", jsonrpc.NewHandler(&Echo{}))

Index

Constants

View Source
const (
	StatusParseError     = -32700 // Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.
	StatusInvalidRequest = -32600 // The JSON sent is not a valid Request object.
	StatusMethodNotFound = -32601 // The method does not exist / is not available.
	StatusInvalidParams  = -32602 // Invalid method parameter(s).
	StatusInternalError  = -32603 // Internal JSON-RPC error.
)

JSON-RPC 2.0 reserved status codes.

Variables

This section is empty.

Functions

This section is empty.

Types

type Encoder

type Encoder interface {
	Encode(v interface{}) error
}

Encoder is something that can encode into JSON. By default it is a json.Encoder

type Error

type Error struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
	// contains filtered or unexported fields
}

Error represents a JSON-RPC 2.0 error. If an Error is returned from a registered function, it will be sent directly to the client.

func WrapError

func WrapError(err error) *Error

WrapError creates a JSON-RPC Error by wrapping an underlying error, with StatusInternalError by default. If the wrapped error is also a JSON-RPC error, then it is preserved.

func (*Error) Error

func (err *Error) Error() string

func (*Error) Unwrap

func (err *Error) Unwrap() error

type Handler

type Handler struct {
	// Encoder configures what encoder will be used for sending JSON-RPC
	// responses. By default the Handler will use json.NewEncoder.
	Encoder func(w io.Writer) Encoder

	// RequestInterceptor, if specified, will be called after the JSON-RPC
	// message is parsed but before the method is called. The Request may be
	// modified.
	//
	// This can be used, for example, to perform handler-wide validation.
	//
	// If an error is returned, the method is never called and that error will
	// be sent to the client instead.
	RequestInterceptor func(ctx context.Context, req *Request) error

	// ResponseInterceptor, if specified, will be called after the method is
	// called but before the response is sent to the client. The Response may
	// be modified.
	//
	// If an error is returned, that error will be sent to the client instead.
	ResponseInterceptor func(ctx context.Context, req Request, res *Response) error
	// contains filtered or unexported fields
}

Handler is an http.Handler that responds to JSON-RPC 2.0 requests.

func NewHandler

func NewHandler(rcvrs ...interface{}) *Handler

NewHandler initializes a new Handler. If receivers are provided, they will be registered.

func (*Handler) Register

func (h *Handler) Register(rcvr interface{})

Register is a convenience function. It will call RegisterMethod on each method of the provided receiver. The registered method name will follow the pattern "Type.Method".

func (*Handler) RegisterMethod

func (h *Handler) RegisterMethod(name string, fn interface{})

RegisterMethod registers a method under the given name. Methods must be valid functions with the following restrictions:

  • the first parameter may be a context.Context
  • the remaining parameters must be able to unmarshal from JSON
  • return values must be (optionally) a value and (optionally) an error
  • if there is a return value, it must be able to marshal as JSON

If the first parameter is a context.Context, then it will receive the context from the HTTP request.

func (*Handler) RegisterName

func (h *Handler) RegisterName(name string, rcvr interface{})

RegisterName is like Register but uses the provided name for the type instead of the receiver's concrete type.

func (*Handler) ServeConn

func (h *Handler) ServeConn(ctx context.Context, rw io.ReadWriter)

ServeConn provides JSON-RPC over any bi-directional stream.

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Request

type Request struct {
	Method string
	Params json.RawMessage
}

Request is unmarshalled before every JSON-RPC call. It contains the raw message and params from the JSON-RPC message.

type Response

type Response struct {
	Result interface{}
	Error  *Error
}

Response contains the results of a JSON-RPC call, and will be marshalled as a JSON-RPC message.

Jump to

Keyboard shortcuts

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