expose

package module
v0.0.0-...-c5572cb Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2024 License: MIT Imports: 13 Imported by: 0

README

Godoc: https://pkg.go.dev/github.com/pbedat/expose

exposeRPC

exposeRPC allows you to create RPC interfaces, without the usual boilerplate. Methods can be exposed directly in Go code, without any further generation or definition steps. The resulting http interface provides an OpenAPI specification, that can be used to create type safe clients, to call the functions you exposed.

Example

Expose the functions Inc and Get as RPC endpoints:

package main

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

	"github.com/pbedat/expose"
)

var i = &atomic.Int32{}


func Inc(_ context.Context, delta int) (int, error) {
	return int(i.Add(int32(delta))), nil
}

func Get(context.Context, expose.Void) (int, error) {
	return int(i.Load()), nil
}

func main() {
	h, err := expose.NewHandler(
		[]expose.Function{
			expose.Func("/counter/inc", Inc),
			expose.Func("/counter/get", Get),
		},
	)
	if err != nil {
		panic(err)
	}

	http.Handle("/", h)

	http.ListenAndServe(":8000", nil)
}

Perform the RPC calls:

curl -H "content-type: application/json" --data 1 localhost:8000/rpc/counter/inc
curl -X POST localhost:8000/rpc/counter/get
> 1

Get the OpenAPI Spec:

curl localhost:8000/rpc/swagger.json
{
  "components": {
    "schemas": {
      "int": {
        "type": "integer"
      }
    }
  },
  "info": {
    "title": "Starter Example",
    "version": ""
  },
  "openapi": "3.0.2",
  "paths": {
    "/counter/get": {
      "post": {
        "operationId": "counter#get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/int"
                }
              }
            }
          },
          "default": {
            "description": ""
          }
        },
        "tags": ["counter"]
      }
    },
    "/counter/inc": {
      "post": {
        "operationId": "counter#inc",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/int"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/int"
                }
              }
            }
          },
          "default": {
            "description": ""
          }
        },
        "tags": ["counter"]
      }
    }
  },
  "servers": [
    {
      "url": "http://localhost:8000/rpc"
    }
  ]
}

More examples: https://github.com/pbedat/expose/tree/main/examples

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrApplication = errors.New("application error")
View Source
var JsonEncoding = Encoding{
	MimeType: "application/json",
	GetEncoder: func(w io.Writer) Encoder {
		enc := json.NewEncoder(w)
		return EncoderFunc(func(v any) error {
			return enc.Encode(v)
		})
	},
	GetDecoder: func(r io.Reader) Decoder {
		dec := json.NewDecoder(r)

		return DecoderFunc(func(v any) error {
			return dec.Decode(v)
		})
	},
}

Functions

func DefaultSchemaIdentifier

func DefaultSchemaIdentifier(t reflect.Type) string

DefaultSchemaIdentifier creates a schema identifier for the provided type `t` in the form of '<path>.<to>.<my>.<package>.<name>

func GetErrCode

func GetErrCode(err error) (string, bool)

func ReflectSpec

func ReflectSpec(root openapi3.T, fns []Function, opts ...reflectSpecOpt) (openapi3.T, error)

ReflectSpec reflects all provided exposed functions `fns` and generates an openapi3 specification. The provided spec is the template for the resulting specification. Use it e.g. to define the spec info or additional schemas and operations

func SetErrCode

func SetErrCode(err error, code string) error

func ShortSchemaIdentifier

func ShortSchemaIdentifier(t reflect.Type) string

ShortSchemaIdentifier creates a schema identifier for the provided type `t` in the form of '<package.<name>'

func WithSchemaIdentifier

func WithSchemaIdentifier(namer SchemaIdentifier) reflectSpecOpt

WithSchemaIdentifier sets an alternative SchemaIdentifier. Default: DefaultSchemaIdentifier

func WithSchemaMapper

func WithSchemaMapper(mapper SchemaMapper) reflectSpecOpt

Types

type Decoder

type Decoder interface {
	Decode(v any) error
}

type DecoderFunc

type DecoderFunc func(v any) error

func (DecoderFunc) Decode

func (f DecoderFunc) Decode(v any) error

type Encoder

type Encoder interface {
	Encode(v any) error
}

type EncoderFunc

type EncoderFunc func(v any) error

func (EncoderFunc) Encode

func (f EncoderFunc) Encode(v any) error

type Encoding

type Encoding struct {
	MimeType   string
	GetDecoder func(r io.Reader) Decoder
	GetEncoder func(w io.Writer) Encoder
}

Encoding is used for content negotiating. Request arguments and response values are encoded and decoded with the encoding that is matching the `Content-Type` or `Accept` header.

type ErrWithCode

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

func (ErrWithCode) Code

func (e ErrWithCode) Code() string

func (ErrWithCode) Error

func (e ErrWithCode) Error() string

type ErrorHandler

type ErrorHandler func(w http.ResponseWriter, enc Encoder, err error) (handled bool)

ErrorHandler is called, when a exposed function returns an error. Returning `handled == true` cancels any further error handling.

type Function

type Function interface {
	// Name is the name of the exposed function.
	// The name is part of the operationId in the spec.
	Name() string
	// Module is a qualifier, used in the operationId and as tag in the operation.
	Module() string
	// Path is the actual path, where the function is registered
	Path() string
	// Req returns an empty instance of the functions request argument.
	// Used for schema reflection.
	Req() any
	// Res returns an empty instance of the functions result value.
	// Used for schema reflection.
	Res() any
	// Apply calls the actual function by decoding the http request and passing it to the function
	Apply(ctx context.Context, dec Decoder) (any, error)
}

Function defines a function, that should be registered as RPC endpoint in the Handler. It carries all information, that is necessary to include it as an operation in the openapi spec of the Handler, as well as the actual function wrapped in `Apply`

func Func

func Func[TReq any, TRes any](mountpoint string, fn func(ctx context.Context, req TReq) (TRes, error)) Function

Func creates an Function that can be registered with the Handler. The provided `fn` is then callable at the provided path. If you want to expose a function without an input or output parameter, you can parametrize with Void, use FuncVoid or FuncNullary instead.

func FuncNullary

func FuncNullary[TRes any](mountpoint string, fn func(ctx context.Context) (TRes, error)) Function

FuncNullary creates an Function for functions without a request argument. See Func.

func FuncNullaryVoid

func FuncNullaryVoid(mountpoint string, fn func(ctx context.Context) error) Function

FuncNullaryVoid creates an Function for functions without a request argument and return no result. See Func

func FuncVoid

func FuncVoid[TReq any](mountpoint string, fn func(ctx context.Context, req TReq) error) Function

FuncVoid creates an Function for functions that do not return values. Shortcut for using Func with Void as request argument.

type Handler

type Handler struct {
	http.Handler
}

Handler handles RPC requests. See NewHandler

func NewHandler

func NewHandler(fns []Function, options ...HandlerOption) (*Handler, error)

NewHandler creates a http handler, that provides the exposed functions as HTTP POST endpoints. see Handler Requests and responses are encoded with JSON by default. The handler also provides the openapi spec at the path '/swagger.json'

When an exposed function returns an error, the handler will respond with HTTP status 500 Internal Server Error by default. When the error is (see errors.Is) an ErrApplication, the status 422 Unprocessable Entity will be returned instead. Errors can be marked with custom codes SetErrCode, which will be included in the error response. To customize the error handling further, a ErrorHandler can be provided.

type HandlerOption

type HandlerOption func(settings *handlerSettings)

func WithDefaultSpec

func WithDefaultSpec(spec *openapi3.T) HandlerOption

WithDefaultSpec allows you to define a base spec. The handler fills this base spec with the operations and schemas reflected from the exposed functions.

func WithEncodings

func WithEncodings(encodings ...Encoding) HandlerOption

WithEncodings registers additional encodings. Encodings are selected based on the provided "Content-Type" and "Accept" headers

func WithErrorHandler

func WithErrorHandler(h ErrorHandler) HandlerOption

WithErrorHandler registers a custom ErrorHandler

func WithPathPrefix

func WithPathPrefix(prefixPath string) HandlerOption

WithPathPrefix defines the path prefix of the handler. When using it with WithSwaggerUI, make sure that your `Servers` section in the default spec WithDefaultSpec adds this prefix as well

func WithReflection

func WithReflection(opts ...reflectSpecOpt) HandlerOption

WithReflection sets options for the schema reflection

func WithSwaggerJSONPath

func WithSwaggerJSONPath(path string) HandlerOption

WithSwaggerJSONPath overrides the default path (/swagger.json), where the spec is served

func WithSwaggerUI

func WithSwaggerUI(path string) HandlerOption

WithSwaggerUI, adds a SwaggerUI handler at the provided `path`

type Middleware

type Middleware func(next http.Handler) http.Handler

type SchemaIdentifier

type SchemaIdentifier func(t reflect.Type) string

TypeNamers are used to generate a schema identifier for a go type

type SchemaMapper

type SchemaMapper func(t reflect.Type) *openapi3.Schema

type SchemaProvider

type SchemaProvider interface {
	JSONSchema(gen *openapi3gen.Generator, schemas openapi3.Schemas) (*openapi3.SchemaRef, error)
}

SchemaProvider overrides the schema reflection with the provided custom type

type SwaggerUIHandler

type SwaggerUIHandler struct {
	http.Handler
}

func NewSwaggerUIHandler

func NewSwaggerUIHandler(defaultSpec openapi3.T, fns []Function) *SwaggerUIHandler

type Void

type Void struct{}

Void is a placeholder for input or output parameters. When an input parameter is Void. The function is treated as nullary. When the output paramtere is Void, the function is treated as function without a return parameter.

func (*Void) UnmarshalJSON

func (v *Void) UnmarshalJSON(b []byte) error

type WithCode

type WithCode interface {
	error
	Code() string
}

Directories

Path Synopsis
examples
exposefx contains helper methods to expose functions to a fx app and to provide the handler
exposefx contains helper methods to expose functions to a fx app and to provide the handler

Jump to

Keyboard shortcuts

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