README
jsonrpc
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
- type Encoder
- type Error
- type Handler
- func (h *Handler) Register(rcvr interface{})
- func (h *Handler) RegisterMethod(name string, fn interface{})
- func (h *Handler) RegisterName(name string, rcvr interface{})
- func (h *Handler) ServeConn(ctx context.Context, rw io.ReadWriter)
- func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)
- type Request
- type Response
Constants ¶
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 ¶
Functions ¶
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.
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 ¶
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 ¶
RegisterName is like Register but uses the provided name for the type instead of the receiver's concrete type.
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.