# JSON RPC [JSON RPC](http://www.jsonrpc.org) 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](https://godoc.org/net/http#Handler), receiving all requests to the JSON RPC's URL. The server looks at the `method` property of the [Request Object](http://www.jsonrpc.org/specification#request_object), and routes it to the corresponding code. Each JSON RPC _method_ is implemented as an `EndpointCodec`, a go-kit [Endpoint](https://godoc.org/github.com/go-kit/kit/endpoint#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 } } ### `EndpointCodecMap` 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`. jsonrpc.EndpointCodecMap{ "sum": jsonrpc.EndpointCodec{ Endpoint: sumEndpoint, Decode: decodeSumRequest, Encode: encodeSumResponse, }, } ### Decoder 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… ### Encoder The encoder takes the output of the endpoint, and builds the raw JSON message that will form the `result` field of a [Response Object](http://www.jsonrpc.org/specification#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 } ### Server 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 }