zenrpc

package module
v1.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2019 License: MIT Imports: 15 Imported by: 4

README

zenrpc: JSON-RPC 2.0 Server Implementation with SMD support

Go Report Card Build Status codecov GoDoc

zenrpc is a JSON-RPC 2.0 server library with Service Mapping Description support. It's built on top of go generate instead of reflection.

How to Use

Service is struct with RPC methods, service represents RPC namespace.

  1. Install zenrpc generator go get github.com/semrush/zenrpc/zenrpc
  2. Import github.com/semrush/zenrpc into our code with rpc service.
  3. Add trailing comment //zenrpc to your service or embed zenrpc.Service into your service struct.
  4. Write your funcs almost as usual.
  5. Do not forget run go generate or zenrpc for magic
Accepted Method Signatures
func(Service) Method([args]) (<value>, <error>)
func(Service) Method([args]) <value>
func(Service) Method([args]) <error>
func(Service) Method([args])
  • Value could be a pointer
  • Error is error or *zenrpc.Error

Example

package main

import (
	"flag"
	"context"
	"errors"
	"math"
	"log"
	"net/http"
	"os"	
	
	"github.com/semrush/zenrpc"
	"github.com/semrush/zenrpc/testdata"
)

type ArithService struct{ zenrpc.Service }

// Sum sums two digits and returns error with error code as result and IP from context.
func (as ArithService) Sum(ctx context.Context, a, b int) (bool, *zenrpc.Error) {
	r, _ := zenrpc.RequestFromContext(ctx)

	return true, zenrpc.NewStringError(a+b, r.Host)
}

// Multiply multiples two digits and returns result.
func (as ArithService) Multiply(a, b int) int {
	return a * b
}

type Quotient struct {
	Quo, Rem int
}

func (as ArithService) Divide(a, b int) (quo *Quotient, err error) {
	if b == 0 {
		return nil, errors.New("divide by zero")
	} else if b == 1 {
		return nil, zenrpc.NewError(401, errors.New("we do not serve 1"))
	}

	return &Quotient{
		Quo: a / b,
		Rem: a % b,
	}, nil
}

// Pow returns x**y, the base-x exponential of y. If Exp is not set then default value is 2.
//zenrpc:exp=2
func (as ArithService) Pow(base float64, exp float64) float64 {
	return math.Pow(base, exp)
}

//go:generate zenrpc

func main() {
	addr := flag.String("addr", "localhost:9999", "listen address")
	flag.Parse()

	rpc := zenrpc.NewServer(zenrpc.Options{ExposeSMD: true})
	rpc.Register("arith", testdata.ArithService{})
	rpc.Register("", testdata.ArithService{}) // public
	rpc.Use(zenrpc.Logger(log.New(os.Stderr, "", log.LstdFlags)))

	http.Handle("/", rpc)

	log.Printf("starting arithsrv on %s", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}

Magic comments

All comments are optional.

Method comments
//zenrpc:<method parameter>[=<default value>][whitespaces<description>]
//zenrpc:<error code>[whitespaces<description>]
//zenrpc:return[whitespaces<description>]
 
Struct comments
type MyService struct {} //zenrpc

JSON-RPC 2.0 Supported Features

  • Requests
    • Single requests
    • Batch requests
    • Notifications
  • Parameters
    • Named
    • Position
    • Default values
  • SMD Schema
    • Input
    • Output
    • Codes
    • Scopes for OAuth

Server Library Features

  • go generate
  • Transports
    • HTTP
    • WebSocket
    • RabbitMQ
  • Server middleware
    • Basic support
    • Metrics
    • Logging

Documentation

Index

Constants

View Source
const (
	// ParseError is error code defined by JSON-RPC 2.0 spec.
	// Invalid JSON was received by the server.
	// An error occurred on the server while parsing the JSON text.
	ParseError = -32700

	// InvalidRequest is error code defined by JSON-RPC 2.0 spec.
	// The JSON sent is not as valid Request object.
	InvalidRequest = -32600

	// MethodNotFound is error code defined by JSON-RPC 2.0 spec.
	// The method does not exist / is not available.
	MethodNotFound = -32601

	// InvalidParams is error code defined by JSON-RPC 2.0 spec.
	// Invalid method parameter(s).
	InvalidParams = -32602

	// InternalError is error code defined by JSON-RPC 2.0 spec.
	// Internal JSON-RPC error.
	InternalError = -32603

	// ServerError is error code defined by JSON-RPC 2.0 spec.
	// Reserved for implementation-defined server-errors.
	ServerError = -32000

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

	// context key for ID.
	IDKey contextKey = "id"
)

Variables

This section is empty.

Functions

func ConvertToObject

func ConvertToObject(keys []string, params json.RawMessage) (json.RawMessage, error)

ConvertToObject converts json array into object using key by index from keys array.

func ErrorMsg

func ErrorMsg(code int) string

ErrorMsg returns error as text for default JSON-RPC errors.

func IDFromContext added in v1.0.1

func IDFromContext(ctx context.Context) *json.RawMessage

IDFromContext returns request ID from context.

func IsArray

func IsArray(message json.RawMessage) bool

IsArray checks json message if it array or object.

func NamespaceFromContext

func NamespaceFromContext(ctx context.Context) string

NamespaceFromContext returns method's namespace from context.

func RequestFromContext

func RequestFromContext(ctx context.Context) (*http.Request, bool)

RequestFromContext returns http.Request from context.

func SMDBoxHandler

func SMDBoxHandler(w http.ResponseWriter, r *http.Request)

SMDBoxHandler is a handler for SMDBox web app.

Types

type Error

type Error struct {
	// A Number that indicates the error type that occurred.
	// This MUST be an integer.
	Code int `json:"code"`

	// A String providing as short description of the error.
	// The message SHOULD be limited to as concise single sentence.
	Message string `json:"message"`

	// A Primitive or Structured value that contains additional information about the error.
	// This may be omitted.
	// The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).
	Data interface{} `json:"data,omitempty"`

	// Err is inner error.
	Err error `json:"-"`
}

Error object used in response if function call errored. See: http://www.jsonrpc.org/specification#error_object

func NewError

func NewError(code int, err error) *Error

NewError makes a JSON-RPC error with given code and standard error.

func NewStringError

func NewStringError(code int, message string) *Error

NewStringError makes a JSON-RPC with given code and message.

func (Error) Error

func (e Error) Error() string

Error returns first filled value from Err, Message or default text for JSON-RPC error.

type InvokeFunc

type InvokeFunc func(context.Context, string, json.RawMessage) Response

InvokeFunc is a function for processing single JSON-RPC 2.0 Request after validation and parsing.

type Invoker

type Invoker interface {
	Invoke(ctx context.Context, method string, params json.RawMessage) Response
	SMD() smd.ServiceInfo
}

Invoker implements service handler.

type MiddlewareFunc

type MiddlewareFunc func(InvokeFunc) InvokeFunc

MiddlewareFunc is a function for executing as middleware.

func Logger

func Logger(l *log.Logger) MiddlewareFunc

Logger is middleware for JSON-RPC 2.0 Server. It's just an example for middleware, will be refactored later.

func Metrics

func Metrics(appName string) MiddlewareFunc

Metrics is a middleware for logging duration of RPC requests via Prometheus. Default AppName is zenrpc. It exposes two metrics: appName_rpc_error_requests_count and appName_rpc_responses_duration_seconds.

type Options

type Options struct {
	// BatchMaxLen sets maximum quantity of requests in single batch.
	BatchMaxLen int

	// TargetURL is RPC endpoint.
	TargetURL string

	// ExposeSMD exposes SMD schema with ?smd GET parameter.
	ExposeSMD bool

	// DisableTransportChecks disables Content-Type and methods checks. Use only for development mode.
	DisableTransportChecks bool

	// AllowCORS adds header Access-Control-Allow-Origin with *.
	AllowCORS bool

	// Upgrader sets options for gorilla websocket. If nil, default options will be used
	Upgrader *websocket.Upgrader

	// HideErrorDataField removes data field from response error
	HideErrorDataField bool
}

Options is options for JSON-RPC 2.0 Server.

type Printer

type Printer interface {
	Printf(string, ...interface{})
}

type Request

type Request struct {
	// A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0".
	Version string `json:"jsonrpc"`

	// An identifier established by the Client that MUST contain as String, Number, or NULL value if included.
	// If it is not included it is assumed to be as notification.
	// The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts.
	ID *json.RawMessage `json:"id"`

	// A String containing the name of the method to be invoked.
	// Method names that begin with the word rpc followed by as period character (U+002E or ASCII 46)
	// are reserved for rpc-internal methods and extensions and MUST NOT be used for anything else.
	Method string `json:"method"`

	// A Structured value that holds the parameter values to be used during the invocation of the method.
	// This member MAY be omitted.
	Params json.RawMessage `json:"params"`

	// Namespace holds namespace. Not in spec, for internal needs.
	Namespace string `json:"-"`
}

Request is a json structure for json-rpc request to server. See: http://www.jsonrpc.org/specification#request_object

type Response

type Response struct {
	// A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0".
	Version string `json:"jsonrpc"`

	// This member is REQUIRED.
	// It MUST be the same as the value of the id member in the Request Object.
	// If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), it MUST be Null.
	ID *json.RawMessage `json:"id"`

	// This member is REQUIRED on success.
	// This member MUST NOT exist if there was an error invoking the method.
	// The value of this member is determined by the method invoked on the Server.
	Result *json.RawMessage `json:"result,omitempty"`

	// This member is REQUIRED on error.
	// This member MUST NOT exist if there was no error triggered during invocation.
	// The value for this member MUST be an Object as defined in section 5.1.
	Error *Error `json:"error,omitempty"`

	// Extensions is additional field for extending standard response. It could be useful for tracing, method execution, etc...
	Extensions map[string]interface{} `json:"extensions,omitempty"`
}

Response is json structure for json-rpc response from server. See: http://www.jsonrpc.org/specification#response_object

func NewResponseError

func NewResponseError(id *json.RawMessage, code int, message string, data interface{}) Response

NewResponseError returns new Response with Error object.

func (Response) JSON

func (r Response) JSON() []byte

JSON is temporary method that silences error during json marshalling.

func (*Response) Set

func (r *Response) Set(v interface{}, er ...error)

Set sets result and error if needed.

type Server

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

Server is JSON-RPC 2.0 Server.

func NewServer

func NewServer(opts Options) Server

NewServer returns new JSON-RPC 2.0 Server.

func (Server) Do added in v1.1.0

func (s Server) Do(ctx context.Context, req []byte) ([]byte, error)

Do process JSON-RPC 2.0 request, invokes correct method for namespace and returns JSON-RPC 2.0 Response or marshaller error.

func (*Server) Register

func (s *Server) Register(namespace string, service Invoker)

Register registers new service for given namespace. For public namespace use empty string.

func (*Server) RegisterAll

func (s *Server) RegisterAll(services map[string]Invoker)

RegisterAll registers all services listed in map.

func (Server) SMD

func (s Server) SMD() smd.Schema

SMD returns Service Mapping Description object with all registered methods.

func (Server) ServeHTTP

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

ServeHTTP process JSON-RPC 2.0 requests via HTTP. http://www.simple-is-better.org/json-rpc/transport_http.html

func (Server) ServeWS

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

ServeWS processes JSON-RPC 2.0 requests via Gorilla WebSocket. https://github.com/gorilla/websocket/blob/master/examples/echo/

func (*Server) SetLogger

func (s *Server) SetLogger(printer Printer)

SetLogger sets logger for debug

func (*Server) Use

func (s *Server) Use(m ...MiddlewareFunc)

Use registers middleware.

type Service

type Service struct{}

Service is as struct for discovering JSON-RPC 2.0 services for zenrpc generator cmd.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL