README

jsonrpc

Travis branch codecov Go Report Card codebeat badge Maintainability GoDoc GitHub license

About

  • Simple, Poetic, Pithy.
  • No reflect package.
    • But reflect package is used only when invoke the debug handler.
  • Support GAE/Go Standard Environment.
  • Compliance with JSON-RPC 2.0.

Note: If you use Go 1.6, see v1.0.

Install

$ go get -u github.com/osamingo/jsonrpc

Usage

package main

import (
	"context"
	"log"
	"net/http"

	"github.com/intel-go/fastjson"
	"github.com/osamingo/jsonrpc"
)

type (
	EchoHandler struct{}
	EchoParams  struct {
		Name string `json:"name"`
	}
	EchoResult struct {
		Message string `json:"message"`
	}

	PositionalHandler struct{}
	PositionalParams  []int
	PositionalResult  struct {
		Message []int `json:"message"`
	}
)

func (h EchoHandler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {

	var p EchoParams
	if err := jsonrpc.Unmarshal(params, &p); err != nil {
		return nil, err
	}

	return EchoResult{
		Message: "Hello, " + p.Name,
	}, nil
}

func (h PositionalHandler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *Error) {

	var p PositionalParams
	if err := jsonrpc.Unmarshal(params, &p); err != nil {
		return nil, err
	}

	return PositionalResult{
		Message: p,
	}, nil
}

func main() {

	mr := jsonrpc.NewMethodRepository()

	if err := mr.RegisterMethod("Main.Echo", EchoHandler{}, EchoParams{}, EchoResult{}); err != nil {
		log.Fatalln(err)
	}

	if err := mr.RegisterMethod("Main.Positional", PositionalHandler{}, PositionalParams{}, PositionalResult{}); err != nil {
		log.Fatalln(err)
	}

	http.Handle("/jrpc", mr)
	http.HandleFunc("/jrpc/debug", mr.ServeDebug)

	if err := http.ListenAndServe(":8080", http.DefaultServeMux); err != nil {
		log.Fatalln(err)
	}
}
Advanced
package main

import (
	"log"
	"net/http"

	"github.com/osamingo/jsonrpc"
)

type (
	HandleParamsResulter interface {
		jsonrpc.Handler
		Name() string
		Params() interface{}
		Result() interface{}
	}
	Servicer interface {
		MethodName(HandleParamsResulter) string
		Handlers() []HandleParamsResulter
	}
	UserService struct {
		SignUpHandler HandleParamsResulter
		SignInHandler HandleParamsResulter
	}
)

func (us *UserService) MethodName(h HandleParamsResulter) string {
	return "UserService." + h.Name()
}

func (us *UserService) Handlers() []HandleParamsResulter {
	return []HandleParamsResulter{us.SignUpHandler, us.SignInHandler}
}

func NewUserService() *UserService {
	return &UserService{
	// Initialize handlers
	}
}

func main() {

	mr := jsonrpc.NewMethodRepository()

	for _, s := range []Servicer{NewUserService()} {
		for _, h := range s.Handlers() {
			mr.RegisterMethod(s.MethodName(h), h, h.Params(), h.Result())
		}
	}

	http.Handle("/jrpc", mr)
	http.HandleFunc("/jrpc/debug", mr.ServeDebug)

	if err := http.ListenAndServe(":8080", http.DefaultServeMux); err != nil {
		log.Fatalln(err)
	}
}
Result
Invoke the Echo method
POST /jrpc HTTP/1.1
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 82
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/0.9.6

{
  "jsonrpc": "2.0",
  "method": "Main.Echo",
  "params": {
    "name": "John Doe"
  },
  "id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}

HTTP/1.1 200 OK
Content-Length: 68
Content-Type: application/json
Date: Mon, 28 Nov 2016 13:48:13 GMT

{
  "jsonrpc": "2.0",
  "result": {
    "message": "Hello, John Doe"
  },
  "id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}
Invoke the Positional method
POST /jrpc HTTP/1.1
Accept: */*
Content-Length: 133
Content-Type: application/json
Host: localhost:8080
User-Agent: curl/7.61.1

{
  "jsonrpc": "2.0",
  "method": "Main.Positional",
  "params": [3,1,1,3,5,3],
  "id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}

HTTP/1.1 200 OK
Content-Length: 97
Content-Type: application/json
Date: Mon, 05 Nov 2018 11:23:35 GMT

{
  "jsonrpc": "2.0",
  "result": {
    "message": [3,1,1,3,5,3]
  },
  "id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b"
}

Access to debug handler
GET /jrpc/debug HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8080
User-Agent: HTTPie/0.9.6

HTTP/1.1 200 OK
Content-Length: 408
Content-Type: application/json
Date: Mon, 28 Nov 2016 13:56:24 GMT

[
  {
    "handler": "EchoHandler",
    "name": "Main.Echo",
    "params": {
      "$ref": "#/definitions/EchoParams",
      "$schema": "http://json-schema.org/draft-04/schema#",
      "definitions": {
        "EchoParams": {
          "additionalProperties": false,
          "properties": {
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "type": "object"
        }
      }
    },
    "result": {
      "$ref": "#/definitions/EchoResult",
      "$schema": "http://json-schema.org/draft-04/schema#",
      "definitions": {
        "EchoResult": {
          "additionalProperties": false,
          "properties": {
            "message": {
              "type": "string"
            }
          },
          "required": [
            "message"
          ],
          "type": "object"
        }
      }
    }
  }
]

License

Released under the MIT License.

Expand ▾ Collapse ▴

Documentation

Overview

    Package jsonrpc helps JSON-RPC 2.0 implements.

    Index

    Constants

    View Source
    const (
    	// Version is JSON-RPC 2.0.
    	Version = "2.0"
    )

    Variables

    This section is empty.

    Functions

    func ParseRequest

    func ParseRequest(r *http.Request) ([]*Request, bool, *Error)

      ParseRequest parses a HTTP request to JSON-RPC request.

      func RequestID

      func RequestID(c context.Context) *bijson.RawMessage

        RequestID takes request id from context.

        func SendResponse

        func SendResponse(w http.ResponseWriter, resp []*Response, batch bool) error

          SendResponse writes JSON-RPC response.

          func WithRequestID

          func WithRequestID(c context.Context, id *bijson.RawMessage) context.Context

            WithRequestID adds request id to context.

            Types

            type Error

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

              An Error is a wrapper for a JSON interface value.

              func ErrInternal

              func ErrInternal() *Error

                ErrInternal returns internal error.

                func ErrInvalidParams

                func ErrInvalidParams() *Error

                  ErrInvalidParams returns invalid params error.

                  func ErrInvalidRequest

                  func ErrInvalidRequest() *Error

                    ErrInvalidRequest returns invalid request error.

                    func ErrMethodNotFound

                    func ErrMethodNotFound() *Error

                      ErrMethodNotFound returns method not found error.

                      func ErrParse

                      func ErrParse() *Error

                        ErrParse returns parse error.

                        func Unmarshal

                        func Unmarshal(params *bijson.RawMessage, dst interface{}) *Error

                          Unmarshal decodes JSON-RPC params.

                          func (*Error) Error

                          func (e *Error) Error() string

                            Error implements error interface.

                            type ErrorCode

                            type ErrorCode int

                              A ErrorCode by JSON-RPC 2.0.

                              const (
                              	// ErrorCodeParse is parse error code.
                              	ErrorCodeParse ErrorCode = -32700
                              	// ErrorCodeInvalidRequest is invalid request error code.
                              	ErrorCodeInvalidRequest ErrorCode = -32600
                              	// ErrorCodeMethodNotFound is method not found error code.
                              	ErrorCodeMethodNotFound ErrorCode = -32601
                              	// ErrorCodeInvalidParams is invalid params error code.
                              	ErrorCodeInvalidParams ErrorCode = -32602
                              	// ErrorCodeInternal is internal error code.
                              	ErrorCodeInternal ErrorCode = -32603
                              )

                              type Handler

                              type Handler interface {
                              	ServeJSONRPC(c context.Context, params *bijson.RawMessage) (result interface{}, err *Error)
                              }

                                Handler links a method of JSON-RPC request.

                                type Metadata

                                type Metadata struct {
                                	Handler Handler
                                	Params  interface{}
                                	Result  interface{}
                                }

                                  Metadata has method meta data.

                                  type MethodReference

                                  type MethodReference struct {
                                  	Name    string             `json:"name"`
                                  	Handler string             `json:"handler"`
                                  	Params  *jsonschema.Schema `json:"params,omitempty"`
                                  	Result  *jsonschema.Schema `json:"result,omitempty"`
                                  }

                                    A MethodReference is a reference of JSON-RPC method.

                                    type MethodRepository

                                    type MethodRepository struct {
                                    	// contains filtered or unexported fields
                                    }

                                      A MethodRepository has JSON-RPC method functions.

                                      func NewMethodRepository

                                      func NewMethodRepository() *MethodRepository

                                        NewMethodRepository returns new MethodRepository.

                                        func (*MethodRepository) InvokeMethod

                                        func (mr *MethodRepository) InvokeMethod(c context.Context, r *Request) *Response

                                          InvokeMethod invokes JSON-RPC method.

                                          func (*MethodRepository) Methods

                                          func (mr *MethodRepository) Methods() map[string]Metadata

                                            Methods returns registered methods.

                                            func (*MethodRepository) RegisterMethod

                                            func (mr *MethodRepository) RegisterMethod(method string, h Handler, params, result interface{}) error

                                              RegisterMethod registers jsonrpc.Func to MethodRepository.

                                              func (*MethodRepository) ServeDebug

                                              func (mr *MethodRepository) ServeDebug(w http.ResponseWriter, r *http.Request)

                                                ServeDebug views registered method list.

                                                func (*MethodRepository) ServeHTTP

                                                func (mr *MethodRepository) ServeHTTP(w http.ResponseWriter, r *http.Request)

                                                  ServeHTTP provides basic JSON-RPC handling.

                                                  func (*MethodRepository) TakeMethod

                                                  func (mr *MethodRepository) TakeMethod(r *Request) (Handler, *Error)

                                                    TakeMethod takes jsonrpc.Func in MethodRepository.

                                                    type Request

                                                    type Request struct {
                                                    	Version string             `json:"jsonrpc"`
                                                    	Method  string             `json:"method"`
                                                    	Params  *bijson.RawMessage `json:"params"`
                                                    	ID      *bijson.RawMessage `json:"id"`
                                                    }

                                                      A Request represents a JSON-RPC request received by the server.

                                                      type Response

                                                      type Response struct {
                                                      	Version string             `json:"jsonrpc"`
                                                      	Result  interface{}        `json:"result,omitempty"`
                                                      	Error   *Error             `json:"error,omitempty"`
                                                      	ID      *bijson.RawMessage `json:"id,omitempty"`
                                                      }

                                                        A Response represents a JSON-RPC response returned by the server.

                                                        func NewResponse

                                                        func NewResponse(r *Request) *Response

                                                          NewResponse generates a JSON-RPC response.