JSON RPC is "A light weight remote procedure call protocol". It allows for the creation of simple RPC-style APIs with human-readable messages that are front-end friendly.

Using JSON RPC with Go-Kit

Using JSON RPC and go-kit together is quite simple.

A JSON RPC server acts as an HTTP Handler, receiving all requests to the JSON RPC's URL. The server looks at the method property of the Request Object, and routes it to the corresponding code.

Each JSON RPC method is implemented as an EndpointCodec, a go-kit Endpoint, sandwiched between a decoder and encoder. The decoder picks apart the JSON RPC request params, which can be passed to your endpoint. The encoder receives the output from the endpoint and encodes a JSON-RPC result.

Example — Add Service

Let's say we want a service that adds two ints together. We'll serve this at http://localhost/rpc. So a request to our sum method will be a POST to http://localhost/rpc with a request body of:

    "id": 123,
    "jsonrpc": "2.0",
    "method": "sum",
    "params": {
        "A": 2,
        "B": 2

The routing table for incoming JSON RPC requests is the EndpointCodecMap. The key of the map is the JSON RPC method name. Here, we're routing the sum method to an EndpointCodec wrapped around sumEndpoint.

    "sum": jsonrpc.EndpointCodec{
        Endpoint: sumEndpoint,
        Decode:   decodeSumRequest,
        Encode:   encodeSumResponse,
type DecodeRequestFunc func(context.Context, json.RawMessage) (request interface{}, err error)

A DecodeRequestFunc is given the raw JSON from the params property of the Request object, not the whole request object. It returns an object that will be the input to the Endpoint. For our purposes, the output should be a SumRequest, like this:

type SumRequest struct {
    A, B int

So here's our decoder:

func decodeSumRequest(ctx context.Context, msg json.RawMessage) (interface{}, error) {
    var req SumRequest
    err := json.Unmarshal(msg, &req)
    if err != nil {
        return nil, err
    return req, nil

So our SumRequest will now be passed to the endpoint. Once the endpoint has done its work, we hand over to the…


The encoder takes the output of the endpoint, and builds the raw JSON message that will form the result field of a Response Object. Our result is going to be a plain int. Here's our encoder:

func encodeSumResponse(ctx context.Context, result interface{}) (json.RawMessage, error) {
    sum, ok := result.(int)
    if !ok {
        return nil, errors.New("result is not an int")
    b, err := json.Marshal(sum)
    if err != nil {
        return nil, err
    return b, nil

Now that we have an EndpointCodec with decoder, endpoint, and encoder, we can wire up the server:

handler := jsonrpc.NewServer(jsonrpc.EndpointCodecMap{
    "sum": jsonrpc.EndpointCodec{
        Endpoint: sumEndpoint,
        Decode:   decodeSumRequest,
        Encode:   encodeSumResponse,
http.Handle("/rpc", handler)
http.ListenAndServe(":80", nil)

With all of this done, our example request above should result in a response like this:

    "jsonrpc": "2.0",
    "result": 4



    Package jsonrpc provides a JSON RPC (v2.0) binding for endpoints. See



    View Source
    const (
    	// ParseError defines invalid JSON was received by the server.
    	// An error occurred on the server while parsing the JSON text.
    	ParseError int = -32700
    	// InvalidRequestError defines the JSON sent is not a valid Request object.
    	InvalidRequestError int = -32600
    	// MethodNotFoundError defines the method does not exist / is not available.
    	MethodNotFoundError int = -32601
    	// InvalidParamsError defines invalid method parameter(s).
    	InvalidParamsError int = -32602
    	// InternalError defines a server error
    	InternalError int = -32603
    View Source
    const (
    	// Version defines the version of the JSON RPC implementation
    	Version string = "2.0"
    	// ContentType defines the content type to be served.
    	ContentType string = "application/json; charset=utf-8"


    This section is empty.


    func DefaultErrorEncoder

    func DefaultErrorEncoder(_ context.Context, err error, w http.ResponseWriter)

      DefaultErrorEncoder writes the error to the ResponseWriter, as a json-rpc error response, with an InternalError status code. The Error() string of the error will be used as the response error message. If the error implements ErrorCoder, the provided code will be set on the response error. If the error implements Headerer, the given headers will be set.

      func DefaultRequestEncoder

      func DefaultRequestEncoder(_ context.Context, req interface{}) (json.RawMessage, error)

        DefaultRequestEncoder marshals the given request to JSON.

        func DefaultResponseDecoder

        func DefaultResponseDecoder(_ context.Context, res Response) (interface{}, error)

          DefaultResponseDecoder unmarshals the result to interface{}, or returns an error, if found.

          func ErrorMessage

          func ErrorMessage(code int) string

            ErrorMessage returns a message for the JSON RPC error code. It returns the empty string if the code is unknown.


            type Client

            type Client struct {
            	// contains filtered or unexported fields

              Client wraps a JSON RPC method and provides a method that implements endpoint.Endpoint.

              func NewClient

              func NewClient(
              	tgt *url.URL,
              	method string,
              	options ...ClientOption,
              ) *Client

                NewClient constructs a usable Client for a single remote method.

                func (Client) Endpoint

                func (c Client) Endpoint() endpoint.Endpoint

                  Endpoint returns a usable endpoint that invokes the remote endpoint.

                  type ClientFinalizerFunc

                  type ClientFinalizerFunc func(ctx context.Context, err error)

                    ClientFinalizerFunc can be used to perform work at the end of a client HTTP request, after the response is returned. The principal intended use is for error logging. Additional response parameters are provided in the context under keys with the ContextKeyResponse prefix. Note: err may be nil. There maybe also no additional response parameters depending on when an error occurs.

                    type ClientOption

                    type ClientOption func(*Client)

                      ClientOption sets an optional parameter for clients.

                      func BufferedStream

                      func BufferedStream(buffered bool) ClientOption

                        BufferedStream sets whether the Response.Body is left open, allowing it to be read from later. Useful for transporting a file as a buffered stream.

                        func ClientAfter

                        func ClientAfter(after ...httptransport.ClientResponseFunc) ClientOption

                          ClientAfter sets the ClientResponseFuncs applied to the server's HTTP response prior to it being decoded. This is useful for obtaining anything from the response and adding onto the context prior to decoding.

                          func ClientBefore

                          func ClientBefore(before ...httptransport.RequestFunc) ClientOption

                            ClientBefore sets the RequestFuncs that are applied to the outgoing HTTP request before it's invoked.

                            func ClientFinalizer

                              ClientFinalizer is executed at the end of every HTTP request. By default, no finalizer is registered.

                              func ClientRequestEncoder

                              func ClientRequestEncoder(enc EncodeRequestFunc) ClientOption

                                ClientRequestEncoder sets the func used to encode the request params to JSON. If not set, DefaultRequestEncoder is used.

                                func ClientRequestIDGenerator

                                func ClientRequestIDGenerator(g RequestIDGenerator) ClientOption

                                  ClientRequestIDGenerator is executed before each request to generate an ID for the request. By default, AutoIncrementRequestID is used.

                                  func ClientResponseDecoder

                                  func ClientResponseDecoder(dec DecodeResponseFunc) ClientOption

                                    ClientResponseDecoder sets the func used to decode the response params from JSON. If not set, DefaultResponseDecoder is used.

                                    func SetClient

                                    func SetClient(client httptransport.HTTPClient) ClientOption

                                      SetClient sets the underlying HTTP client used for requests. By default, http.DefaultClient is used.

                                      type DecodeRequestFunc

                                      type DecodeRequestFunc func(context.Context, json.RawMessage) (request interface{}, err error)

                                        DecodeRequestFunc extracts a user-domain request object from raw JSON It's designed to be used in JSON RPC servers, for server-side endpoints. One straightforward DecodeRequestFunc could be something that unmarshals JSON from the request body to the concrete request type.

                                        type DecodeResponseFunc

                                        type DecodeResponseFunc func(context.Context, Response) (response interface{}, err error)

                                          DecodeResponseFunc extracts a user-domain response object from an JSON RPC response object. It's designed to be used in JSON RPC clients, for client-side endpoints. It is the responsibility of this function to decide whether any error present in the JSON RPC response should be surfaced to the client endpoint.

                                          type EncodeRequestFunc

                                          type EncodeRequestFunc func(context.Context, interface{}) (request json.RawMessage, err error)

                                            EncodeRequestFunc encodes the given request object to raw JSON. It's designed to be used in JSON RPC clients, for client-side endpoints. One straightforward EncodeResponseFunc could be something that JSON encodes the object directly.

                                            type EncodeResponseFunc

                                            type EncodeResponseFunc func(context.Context, interface{}) (response json.RawMessage, err error)

                                              EncodeResponseFunc encodes the passed response object to a JSON RPC result. It's designed to be used in HTTP servers, for server-side endpoints. One straightforward EncodeResponseFunc could be something that JSON encodes the object directly.

                                              type EndpointCodec

                                              type EndpointCodec struct {
                                              	Endpoint endpoint.Endpoint
                                              	Decode   DecodeRequestFunc
                                              	Encode   EncodeResponseFunc

                                                EndpointCodec defines a server Endpoint and its associated codecs

                                                type EndpointCodecMap

                                                type EndpointCodecMap map[string]EndpointCodec

                                                  EndpointCodecMap maps the Request.Method to the proper EndpointCodec

                                                  type Error

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

                                                    Error defines a JSON RPC error that can be returned in a Response from the spec

                                                    func (Error) Error

                                                    func (e Error) Error() string

                                                      Error implements error.

                                                      func (Error) ErrorCode

                                                      func (e Error) ErrorCode() int

                                                        ErrorCode returns the JSON RPC error code associated with the error.

                                                        type ErrorCoder

                                                        type ErrorCoder interface {
                                                        	ErrorCode() int

                                                          ErrorCoder is checked by DefaultErrorEncoder. If an error value implements ErrorCoder, the integer result of ErrorCode() will be used as the JSONRPC error code when encoding the error.

                                                          By default, InternalError (-32603) is used.

                                                          type Request

                                                          type Request struct {
                                                          	JSONRPC string          `json:"jsonrpc"`
                                                          	Method  string          `json:"method"`
                                                          	Params  json.RawMessage `json:"params"`
                                                          	ID      *RequestID      `json:"id"`

                                                            Request defines a JSON RPC request from the spec

                                                            type RequestID

                                                            type RequestID struct {
                                                            	// contains filtered or unexported fields

                                                              RequestID defines a request ID that can be string, number, or null. 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.

                                                              func (*RequestID) Float32

                                                              func (id *RequestID) Float32() (float32, error)

                                                                Float32 returns the ID as a float value. An error is returned if the ID can't be treated as an float.

                                                                func (*RequestID) Int

                                                                func (id *RequestID) Int() (int, error)

                                                                  Int returns the ID as an integer value. An error is returned if the ID can't be treated as an int.

                                                                  func (*RequestID) MarshalJSON

                                                                  func (id *RequestID) MarshalJSON() ([]byte, error)

                                                                  func (*RequestID) String

                                                                  func (id *RequestID) String() (string, error)

                                                                    String returns the ID as a string value. An error is returned if the ID can't be treated as an string.

                                                                    func (*RequestID) UnmarshalJSON

                                                                    func (id *RequestID) UnmarshalJSON(b []byte) error

                                                                      UnmarshalJSON satisfies json.Unmarshaler

                                                                      type RequestIDGenerator

                                                                      type RequestIDGenerator interface {
                                                                      	Generate() interface{}

                                                                        RequestIDGenerator returns an ID for the request.

                                                                        func NewAutoIncrementID

                                                                        func NewAutoIncrementID(init uint64) RequestIDGenerator

                                                                          NewAutoIncrementID returns an auto-incrementing request ID generator, initialised with the given value.

                                                                          type Response

                                                                          type Response struct {
                                                                          	JSONRPC string          `json:"jsonrpc"`
                                                                          	Result  json.RawMessage `json:"result,omitempty"`
                                                                          	Error   *Error          `json:"error,omitempty"`
                                                                          	ID      *RequestID      `json:"id"`

                                                                            Response defines a JSON RPC response from the spec

                                                                            type Server

                                                                            type Server struct {
                                                                            	// contains filtered or unexported fields

                                                                              Server wraps an endpoint and implements http.Handler.

                                                                              func NewServer

                                                                              func NewServer(
                                                                              	ecm EndpointCodecMap,
                                                                              	options ...ServerOption,
                                                                              ) *Server

                                                                                NewServer constructs a new server, which implements http.Server.

                                                                                func (Server) ServeHTTP

                                                                                func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

                                                                                  ServeHTTP implements http.Handler.

                                                                                  type ServerOption

                                                                                  type ServerOption func(*Server)

                                                                                    ServerOption sets an optional parameter for servers.

                                                                                    func ServerAfter

                                                                                    func ServerAfter(after ...httptransport.ServerResponseFunc) ServerOption

                                                                                      ServerAfter functions are executed on the HTTP response writer after the endpoint is invoked, but before anything is written to the client.

                                                                                      func ServerBefore

                                                                                      func ServerBefore(before ...httptransport.RequestFunc) ServerOption

                                                                                        ServerBefore functions are executed on the HTTP request object before the request is decoded.

                                                                                        func ServerErrorEncoder

                                                                                        func ServerErrorEncoder(ee httptransport.ErrorEncoder) ServerOption

                                                                                          ServerErrorEncoder is used to encode errors to the http.ResponseWriter whenever they're encountered in the processing of a request. Clients can use this to provide custom error formatting and response codes. By default, errors will be written with the DefaultErrorEncoder.

                                                                                          func ServerErrorLogger

                                                                                          func ServerErrorLogger(logger log.Logger) ServerOption

                                                                                            ServerErrorLogger is used to log non-terminal errors. By default, no errors are logged. This is intended as a diagnostic measure. Finer-grained control of error handling, including logging in more detail, should be performed in a custom ServerErrorEncoder or ServerFinalizer, both of which have access to the context.

                                                                                            func ServerFinalizer

                                                                                              ServerFinalizer is executed at the end of every HTTP request. By default, no finalizer is registered.