Documentation
¶
Overview ¶
Package jsonrpc serves JSON-RPC 2.0 (https://www.jsonrpc.org/specification) over HTTP. A Server is an http.Handler, so it mounts on the router like any handler and the router's middleware (auth, rate limits, request ids, logging, tracing) applies to every call:
rpc := jsonrpc.NewServer(jsonrpc.Config{Logger: app.Logger})
jsonrpc.Method(rpc, "items.get", func(ctx context.Context, p GetItem) (Item, error) {
return items.Find(ctx, p.ID)
})
r.Handle("POST /rpc", rpc)
Params are a JSON object (or an array, matched to P's fields in order) decoded into P and validated with its `validate` tags (z.For); unknown members are rejected. Errors map to JSON-RPC error objects: an *Error as is, an *errs.ValidationError to -32602, a 4xx *errs.HTTPError to -32000-(status-400) with its client-safe message, anything else (and a panic) to -32603 without details, logged with Config.Logger.
See https://github.com/AlexGalhardo/vukem/blob/main/docs/api.md#json-rpc.
Index ¶
Constants ¶
const ( CodeParseError = -32700 CodeInvalidRequest = -32600 CodeMethodNotFound = -32601 CodeInvalidParams = -32602 CodeInternalError = -32603 )
Standard error codes of the specification.
const OpenRPCVersion = "1.3.2"
OpenRPCVersion is the OpenRPC specification version OpenRPC documents.
Variables ¶
This section is empty.
Functions ¶
func Method ¶
func Method[P, R any](s *Server, name string, fn func(context.Context, P) (R, error), guards ...Guard)
Method registers fn as name. P must be a struct (use struct{} for no params). Like http.ServeMux, it panics on a programming error: an empty, reserved ("rpc.") or duplicate name, or a non-struct P.
Types ¶
type Client ¶
type Client struct {
// Header is added to every request (Authorization, for example).
Header http.Header
// contains filtered or unexported fields
}
Client calls a JSON-RPC 2.0 endpoint over HTTP.
c := jsonrpc.NewClient("https://api.example.com/rpc", &http.Client{Timeout: 10 * time.Second})
item, err := jsonrpc.Call[Item](ctx, c, "items.get", GetItem{ID: 7})
A JSON-RPC error answer is returned as an *Error (use errors.AsType).
type Config ¶
type Config struct {
// MaxBatch is the largest batch accepted (default 50); a larger one is
// refused whole with -32600.
MaxBatch int
// MaxBodyBytes caps the request body (default 1 MiB); more is a 413.
MaxBodyBytes int64
// Logger receives internal errors and panics hidden from clients
// (default: discarded).
Logger *slog.Logger
}
Config sets the server limits. Zero values take the defaults.
type Error ¶
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
}
Error is a JSON-RPC error object. Return one from a method to choose the code; Message and Data are sent to the client as they are.
type Guard ¶
Guard runs before a method; a non-nil error is the call's error and the method does not run (for notifications too). Use it for abilities:
func(ctx context.Context) error { return authz.Authorize(ctx, "items.delete") }
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server dispatches JSON-RPC requests to registered methods.
func (*Server) OpenRPC ¶
OpenRPC returns the OpenRPC document (https://spec.open-rpc.org) of the registered methods, ready for encoding/json: one content descriptor per field of the params struct (in order, required from `validate:"required"`), the result schema, and named structs under components.schemas, with the same schemas the OpenAPI export produces. Serve it from a route, or write it to a file for client generators:
r.Get("/rpc/openrpc.json", func(c *web.Ctx) error {
return c.JSON(http.StatusOK, rpc.OpenRPC("Items", "1.0.0"))
})
func (*Server) ServeHTTP ¶
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. Only POST with a JSON body is served (405, 415 otherwise; 413 over MaxBodyBytes). Every JSON-RPC exchange, errors included, is a 200; a request of notifications only is a 204.