handler

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

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

Go to latest
Published: Apr 2, 2018 License: MIT Imports: 3 Imported by: 0

README

go-handle GoDoc Go Report Card

Library for creating handlers from declarative structs for http frameworks like net/http, labstack/echo or any others

Installation

go get github.com/mykytanikitenko/go-handle

Examples

Follow examples in repository

What this library for?

General idea is to create library what helps to divide large handlers into smaller parts (pipes) for easier testing and to focus on writing code what helps to implement business logic and to avoid repeating code

When we write typical application, our api handlers do very typical job for request:

  1. Parse URL parameters
  2. Read request body
  3. Parse JSON
  4. Validate data
  5. Process data (in database, for example)
  6. Create response
  7. Marshal response to json
  8. Finally return it to the client

There are many frameworks what help us to do it in a less straightforward way, for example we don't need to marshal\unmarshal json directly, like we need for net/http. In many others there are builtin validators, DI containers, data serializers, etc. which combined in a huge frameworks like ASP.NET, RoR, Play.

This library propose to declaratively describe your logic in the handler like below and write processors which only required in your application

type GetArticles struct {
	Request struct {
		PageNumber int
		PageSize   int
		Search     string
	}
	Response struct {
		TotalCount int
		Data       []Article
	}
	Services struct {
		ArticlesRepo
	}
}

func (action GetArticles) Action() (interface{}, error) {
	return action.Services.ArticlesRepo.Find(action.Request)
}

Then you write pipe to process parts of request logic. This one to parse request body and bind to "Request" field:

var BindRequestPipe handler.Pipe = func(v reflect.Value, args ...interface{}) (*reflect.Value, error) {
	field := v.FieldByName("Request")

	if !field.IsValid() {
		return nil, nil
	}

	ctx := args[0].(echo.Context)

	if err := ctx.Bind(field.Addr().Interface()); err != nil {
		return nil, err
	}

	return &v, nil
}

(You can find complete examples in examples directory)

How it works

You create your handler type and pass it instance (or function what constructs your type). This library cares to create new instance for each request and process in pipes. Library simply wraps this to into an anonymous function what you can use in any http library or framework

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrorPipesNil     = fmt.Errorf("handler.New: pipesGroup nil")
	ErrorTNil         = fmt.Errorf("handler.New: t nil")
	ErrorConverterNil = fmt.Errorf("handler.New: converter nil")

	ErrorPointerNonStructType   = fmt.Errorf("handler.New: pointer to non-struct type as constructor")
	ErrorNotInterfacebleValue   = fmt.Errorf("handler.New: not interfaceble value")
	ErrorInvalidConstructorType = fmt.Errorf("handler.New: invalid constructor type")

	ErrorTCtorFuncHaveArguments         = fmt.Errorf("handler.New: t ctor func have arguments")
	ErrorTCtorFuncMoreThanOneReturnType = fmt.Errorf("handler.New: t ctor func have more than one return type")
	ErrorTCtorFuncVoid                  = fmt.Errorf("handler.New: t ctor func doesn't return any types")
)
View Source
var AbortPipeGroup *reflect.Value = nil

If pipe returns this value, next pipe in group will not call

Functions

func ContinuePipeGroup

func ContinuePipeGroup(v reflect.Value) *reflect.Value

If pipe returns action reflect value as nil it means that next pipe should not be called

If returns pointer to reflect value, next pipe should be called

func New

func New(pipes PipeGroup, t interface{}, converter Converter) (*handler, error)

New creates new Handler

Types

type Converter

type Converter func(GenericHandlerFunc) interface{}

Converter converts generic handler to specified. It's a function what accepts generic handler and returns new function what converts to desired function what accepts your library or framework

Example:

var EchoHandler handler.Converter = func(f handler.GenericHandlerFunc) interface{} {
	return echo.HandlerFunc(
		func(ctx echo.Context) error {
			return f(ctx)
		},
	)
}

type GenericHandlerFunc

type GenericHandlerFunc func(...interface{}) error

Generic handler represents generic handler func

type Handler

type Handler interface {
	Handler() interface{}
}

Handler represents handler getter

type Pipe

type Pipe func(v reflect.Value, args ...interface{}) (*reflect.Value, error)

Pipe represents a execution pipe in handler

Example:

var BindRequest Pipe = func(instance reflect.Value, args ...interface{}) (reflect.Value, error) {
	context := args[0].(echo.Context)

	if modelValue := instance.FieldByName("Model"); modelValue.IsValid() {
		model := modelValue.Addr().Interface()

		if err := context.Bind(&model); err != nil {
			return nil, context.JSON(http.StatusBadRequest, err)
		}
	}

	return instance, nil
}

type PipeGroup

type PipeGroup []interface{}

PipeGroup represents a group of nested pipes

Example:

var ActionPipes = handler.PipeGroup{
  []handler.Pipe{BindRequestPipe, ValidateRequestPipe},
  []handler.Pipe{CallActionPipe, NoActionsPipe},
}

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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