ep

package module
v0.0.6 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2020 License: MIT Imports: 10 Imported by: 0

README

ep

A miniature framework to reduce code duplication in writing HTTP endpoints

Backlog

  • MUST get kitchen example back to work
  • MUST also add HTTP language negotiation
  • MUST output.Head and input.Check are now optional
  • MUST clean up the config and make config ergonomic
  • MUST allow exec to return a InvalidInput error
  • MUST allow default configuration to be configured
  • MUST test file upload usecase
  • MUST allow (url) query decoding when request body is JSON (first decoder to implement an interface is used?)
  • MUST have an form decoding that just takes an interface to do the actual decoding
  • MUST benchmark worst case sniffing, negotiation and base overhead
  • MUST run with race checker to check for race conditions
  • MUST allow outputs to overwrite the template to use
  • MUST be able to cache output templates
  • MUST be ergonomic to have translated templates as a response, or other (error) customizations
  • MUST fully test coding package
  • MUST find an alternative for comparing error interface values in Render: not needed, users can just retur nil
  • MUST have a better way to debug unexpected error responses for development: add client and server error logging
  • MUST handle panics in the handle, with the server error message rendering, should also be easy to debug
  • MUST re-think usecase of rest endpoint returning error
  • MUST don't write body if response is 204 or other status without a body
  • SHOULD allow configuring defaults for endpoint config
  • SHOULD make the Config method more ergonomic to use
  • SHOULD come with build-in logging support to debug client and server errors
  • SHOULD remove progress keeping from reader
  • SHOULD add more logging methods to the logger to track
  • COULD turn most of the coding tests into table tests
  • COULD provide tooling to make endpoints extremely easy to test
  • COULD provide tooling to fuzz endpoint
  • COULD add Conf constructors for different types of endpoints: Rest, Form
  • COULD make config method on endpoint optional
  • COULD move per endpoint config to where Handler is called instead
  • COULD come with a nice error page for development
  • COULD rename 'epcoding' to just 'coding'
  • COULD rename coding to something else entirely, cofusing with HTTP encoding header name
  • COULD create http request interface for easier testing
  • COULD remove reqProgress counter
  • COULD allow input.Read to return special error that prevents decoding
  • COULD allow output.Head to return special error that prevents encoding
  • COULD better test language negotiation
  • COULD support response buffering for errors that occur halway writing the response
  • COULD allow JSON encoder configuration, i.e: indentation
  • COULD be more flexible with what content get's accepted for decoding: (i.e application/vnd.api+json should match json)
  • COULD allow configuration what content-type will be written for a encoder: i.e: application/vnd.api+json
  • COULD also handle panics in the negotiation code
  • WONT do content-encoding negotiation, complex: https://github.com/nytimes/gziphandler, deserves dedicated package
  • WONT add a H/HF method for endpoints that are just the handle/exec func
  • WONT return an error from handle as well, since that might be a common usecase. We want to motivate to move into exec function

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// SkipEncode can be retured by the output head to prevent any further
	// decoding
	SkipEncode = errors.New("skip encode")
)

Functions

func Decoding

func Decoding(ctx context.Context) (dec epcoding.Decoding)

Decoding will return the request decoding that was determined based on request headers and MIME sniffing. This will only be empty if the server didn't configure any decodings.

func Encoding

func Encoding(ctx context.Context) (enc epcoding.Encoding)

Encoding will return the response encoding as negotiated with the client. This will only be empty if the server didn't specify any supported encodings

func Language

func Language(ctx context.Context) (s string)

Language will return the language as negotiated with the client. This will only be empty if the server didn't provide any languages

func Negotiate

func Negotiate(cfg ConfReader, req *http.Request) *http.Request

Negotiate will look at the requests' headers and set context values for encoding, decoding and language.

Types

type CheckerInput

type CheckerInput interface {
	Input
	Check() (err error)
}

CheckerInput can be implemented by Inputs to allow them to validate themselves

type Conf

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

Conf builds endpoint configuration

func New

func New() *Conf

New inits an empty configuration

func (Conf) ClientErrFactory

func (r Conf) ClientErrFactory() func(err error) Output

ClientErrFactory returns the current client error factory

func (Conf) Copy

func (c Conf) Copy() (cc *Conf)

Copy will duplicate the configuration

func (Conf) Decodings

func (c Conf) Decodings() []epcoding.Decoding

Decodings returns the configured input decodings

func (Conf) Encodings

func (c Conf) Encodings() []epcoding.Encoding

Encodings returns the configured output encodings

func (Conf) Handler

func (c Conf) Handler(ep Endpoint) *Handler

Handler will copy the configuration and make the endpoint as a handler

func (Conf) HandlerFunc

func (c Conf) HandlerFunc(epf EndpointFunc) *Handler

HandlerFunc will copy the configuration the func as a handler

func (Conf) InvalidErrFactory added in v0.0.6

func (r Conf) InvalidErrFactory() func(err error) Output

InvalidErrFactory returns the current invalid input error factory

func (Conf) Languages

func (c Conf) Languages() []string

Languages return the supported languages for this endpoint

func (Conf) Logger added in v0.0.6

func (c Conf) Logger() Logger

Logger returns the configured logger

func (Conf) QueryDecoder

func (c Conf) QueryDecoder() epcoding.URLValuesDecoder

QueryDecoder configures the query to be decoded into the input struct

func (Conf) ServerErrFactory

func (r Conf) ServerErrFactory() func(err error) Output

ServerErrFactory returns the configured factory for server errors

func (*Conf) SetClientErrFactory

func (r *Conf) SetClientErrFactory(f func(err error) Output) *Conf

SetClientErrFactory configures how client error outputs are created

func (*Conf) SetDecodings

func (c *Conf) SetDecodings(decs ...epcoding.Decoding) *Conf

func (*Conf) SetEncodings

func (c *Conf) SetEncodings(encs ...epcoding.Encoding) *Conf

func (*Conf) SetInvalidErrFactory added in v0.0.6

func (r *Conf) SetInvalidErrFactory(f func(err error) Output) *Conf

SetInvalidErrFactory configures how invalid input errors are created

func (*Conf) SetLanguages

func (c *Conf) SetLanguages(langs ...string) *Conf

func (*Conf) SetLogger added in v0.0.6

func (c *Conf) SetLogger(l Logger) *Conf

func (*Conf) SetQueryDecoder

func (c *Conf) SetQueryDecoder(d epcoding.URLValuesDecoder) *Conf

func (*Conf) SetServerErrFactory

func (r *Conf) SetServerErrFactory(f func(err error) Output) *Conf

SetServerErrFactory configures a factory for the creation of server error outputs

func (*Conf) SetValidator

func (c *Conf) SetValidator(v Validator) *Conf

func (Conf) Validator

func (c Conf) Validator() Validator

Validator returns the configured input validator

func (*Conf) WithDecoding

func (c *Conf) WithDecoding(decs ...epcoding.Decoding) *Conf

func (*Conf) WithEncoding

func (c *Conf) WithEncoding(encs ...epcoding.Encoding) *Conf

func (*Conf) WithLanguage

func (c *Conf) WithLanguage(langs ...string) *Conf

type ConfReader

type ConfReader interface {
	Encodings() []epcoding.Encoding
	Decodings() []epcoding.Decoding
	Languages() []string
	Validator() Validator
	Logger() Logger
	QueryDecoder() epcoding.URLValuesDecoder
	ServerErrFactory() func(err error) Output
	ClientErrFactory() func(err error) Output
	InvalidErrFactory() func(err error) Output
}

type Endpoint

type Endpoint interface {
	Handle(*Response, *http.Request)
}

Endpoint can be implemented to descibe an HTTP endpoint

type EndpointFunc

type EndpointFunc func(*Response, *http.Request)

EndpointFunc implements endpoint by providng just the Handle func

func (EndpointFunc) Handle

func (f EndpointFunc) Handle(res *Response, req *http.Request)

type Handler

type Handler struct {
	*Conf
	// contains filtered or unexported fields
}

Handler handles http for certain endpoint

func (Handler) ServeHTTP

func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP allows the endpoint to serve HTTP

type HeaderOutput

type HeaderOutput interface {
	Output
	Head(http.ResponseWriter, *http.Request) error
}

HeaderOutput can be optionally implementedd by outputs to customize the response headers

type Input

type Input interface{}

Input describes what is read from a request as input to the endpoint.

type InvalidInputError added in v0.0.6

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

InvalidInputError can be returned to render to write a response that indicates that the server understood the request but didn't accept the parameters

func InvalidInput

func InvalidInput(e error) *InvalidInputError

InvalidInput creates a error that can be returned to indicate that the client needs to check its parameters

func (*InvalidInputError) Error added in v0.0.6

func (e *InvalidInputError) Error() string

Error implements error interface

func (*InvalidInputError) Unwrap added in v0.0.6

func (e *InvalidInputError) Unwrap() error

Unwrap returns the wrapped error

type Logger added in v0.0.6

type Logger interface {

	// LogServerErrRender is called when the response will render a server error
	LogServerErrRender(err error)

	// LogClientErrRender is called when the response will render a client error
	LogClientErrRender(err error)
}

Logger interface may be implemented to allow the endpoints to provide feedback in what ever way is preferred

type NopLogger added in v0.0.6

type NopLogger struct{}

NopLogger is can be provided to disable logging

func (NopLogger) LogClientErrRender added in v0.0.6

func (l NopLogger) LogClientErrRender(err error)

func (NopLogger) LogServerErrRender added in v0.0.6

func (l NopLogger) LogServerErrRender(err error)

type Output

type Output interface{}

An Output represents one item that results from the endpoint is will be send as the response back to the client.

type Reader

type Reader struct {
	io.Closer
	*bufio.Reader
}

Reader is a buffered reader that keeps track of the number of bytes that have been read.

func NewReader

func NewReader(r io.ReadCloser) *Reader

NewReader turns an unbuffered reader into a buffered read that keeps track of reading progress. The buffer size is 512 bytes to allow MIME sniffing of the readers content

func (*Reader) Sniff

func (r *Reader) Sniff() (ct string)

Sniff will use peek into the reader and tries to determine the content type

type ReaderInput

type ReaderInput interface {
	Input
	Read(r *http.Request) error
}

ReaderInput is an input that may optionally be implemented by inputs to indicate that it has custom logic for reading the request.

type Response

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

Response is an http.ResponseWriter implementation that comes with a host of untility method for common tasks in http handling.

func NewResponse

func NewResponse(
	wr http.ResponseWriter,
	req *http.Request,
	cfg ConfReader,
) (res *Response)

NewResponse initializes a new Response

func (*Response) Bind

func (r *Response) Bind(in Input) (ok bool)

Bind will use the negotiated decoder to populate the input.

func (*Response) Error

func (r *Response) Error() error

Error will return any server, client or validation error that was encountered while formulating the response.

func (*Response) Header

func (r *Response) Header() http.Header

Header implements the http.ResponseWriter's "Header" method

func (*Response) RecoverRender added in v0.0.6

func (r *Response) RecoverRender()

RecoverRender allows the response to recover from a panic in the stack and render an internal server error.

func (*Response) Render

func (r *Response) Render(out Output, err error)

Render will assert the provided error and earlier errors and provide appropriate feedback in the response. If 'err' is not the same error as returned by Validate() it will be handled as a server error.

func (*Response) Validate

func (r *Response) Validate(in Input) (verr error)

Validate will validate the input and return any error. It will first use any struct validator first before using the input's check method.

func (*Response) Write

func (r *Response) Write(b []byte) (int, error)

Write implements the http.ResponseWriter's "Write" method

func (*Response) WriteHeader

func (r *Response) WriteHeader(statusCode int)

WriteHeader implements the http.ResponseWriter's "WriteHeader" method

type StdLogger added in v0.0.6

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

StdLogger creates a logger using the standard library logging package

func NewStdLogger added in v0.0.6

func NewStdLogger(logs *log.Logger) *StdLogger

NewStdLogger inits a new standard library logger. If logs is nil it will use the global logs.* methods for printing

func (StdLogger) LogClientErrRender added in v0.0.6

func (l StdLogger) LogClientErrRender(err error)

func (StdLogger) LogServerErrRender added in v0.0.6

func (l StdLogger) LogServerErrRender(err error)

type Validator

type Validator interface {
	Validate(v interface{}) error
}

Validator may be implemented and configured to allow automatic validation of all endpoint inputs.

Directories

Path Synopsis
Package header provides functions for parsing HTTP headers.
Package header provides functions for parsing HTTP headers.

Jump to

Keyboard shortcuts

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