ep

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2020 License: MIT Imports: 10 Imported by: 0

README

ep

A miniature Go(lang) framework for rapid development of http.Handlers while reducing code duplication and increasing readability. Designed to build both APIs and regular web applications more efficiently while keeping the flexibility that is expected in the Go ecosystem.

Features:

  • Works with any HTTP router that accepts the http.Handler interface
  • Systematic error handling for HTTP handlers with full customization options
  • Automatically encodes and decodes HTTP payloads using content negotation
  • Well tested, benchmarked and depends only on the standard library
  • Supports streaming requests and responses as a first-class citizen

Backlog V0.1

  • SHOULD be able to use error hooks to assert if errors are server, client or something more specific and return relevant output

  • SHOULD allow request hooks to return an error that is both server, or client

  • SHOULD handle panics in handlers as server errors

  • SHOULD add and test xml encoding/decoding

  • SHOULD add and test template encoding (text/html) and figure out how to pass the template name to the encoder

  • SHOULD add and test form decoding

  • SHOULD allow outputs to specify template method that returns the template type directly, not just the name

  • SHOULD make sure that the PrivateError hook also sets the "nosniff" header like the std library

  • SHOULD make it clear that the build-in error hook only creates outputs for ep.Error errors

  • SHOULD should only show negotation errors when bind is actually called, handlers might not even want to decode. I.e a static endpoint that just returns a struct as output. AND:

  • SHOULD move negotiate to new response creation then

  • SHOULD not set error to nil when hooks fail to deliver an output, users should be able to just return an output themselves that implements the error interface

  • SHOULD return 500 when a response hook panics with nil pointer

  • SHOULD should be possible to prevent the body from being rendered, passing nil is not the correct mechanism. But the actual output should still be taken into account. Would be nice if it doesn't require a magic variable from the ep package so it doesn't need to be included everywhere. - Option 1: use reflection to check for nil value in interface CON: Performance: +/-4ns CON: doesn't allow empty body when value is NOT nil PRO: usefull in preventing hooks calling on nil values - Option 2: check for a method outside of response hooks

  • SHOULD be able to bind empty body to allow the implementation to handle it

  • SHOULD also allow Read() method on input that doesn't return error

  • SHOULD write a basic rest example to test and apply v2

  • SHOULD be able to use bind with a Read implementation that reads the body and don't error with no-decoders

  • SHOULD come up with a metter name for the Empty() method

  • SHOULD make sure that the redirect hook behaves identical to the std lib redirect method. Redirect hook checks for a method to determine the url to redirect to, and also asserts the status method on itself or else takes a sensible redirect default - But what if two hooks trigger writeHeader? The first one takes precedense, so redirect hook should be put in front of

  • SHOULD test the redirect hook in the rest example

  • SHOULD test concurrent use of the callable

  • SHOULD benchmark callable compared to non-reflection use

  • SHOULD properly do errors in callable logic

  • SHOULD rename coding and hook to epcoding and ephook

  • SHOULD rename app, should be open to users of the lib. Overloaded term

  • SHOULD make sure that standard error hook returns valid html (as std lib)

  • SHOULD skip rendering of nil pointers besides just nil

  • COULD research if it is possible to reduce the nr of allocations when decoding and encoding. It adds about 14 more allocations compared to the std lib variant.

  • COULD limit the header lenght used during negotiation so it doesn't allow for DDOS attacks

  • COULD make a response hook that sets cookies

  • COULD allow xml/json/form/template encoder/decoder configuration with the option pattern or outputs implementing a certain interface. The latter is more flexible

  • COULD use a default encoding when the client specifies an accept header and none of the encoders match (the first configfured encoding is always the default)

  • COULD lift up the error kind when nesting errors

  • COULD move the error to a separate package if it can fully replace the stdlib errors package

  • COULD detect if decoding should happen for an input based on whether the hooks have read data from the request body instead of checking a magic method on the input.

  • COULD add some (optional) reflect sparkles for creating the handle func since the reflecting can be done out of the hot path. Maybe take inspiration from the std lib rpc package

  • COULD make the response.Render() method take variadic nr of interface{} arguments such that exec methods can return any nr of outputs. response.Bind() might also be able to bind more then one input. Might be usefull if the endpoint has a two distict outputs with different templates and logic? Errors are already different outputs

  • WONT return text/plain if template encoder is specified a text template. each encoder should only return one type of content, we only support html for now

  • WONT add a specific output that renders as nil, instead skipping encoding instead have magic methods that are asserted.

  • WONT prevent hooks from calling interface methods if the value is nil and causing a panic, requires reflect so maybe disable with a flag. It's up to the implementation to check if the value is nil

Backlog V0.0

  • 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
  • MUST allow html template to accept any kind of template (interface), rename to template encoding
  • MUST not server 500 status code if skipEncode is provided as an error to render
  • MUST set default error template to "error.html" it is corresponds to an actual file in the most common case
  • SHOULD implement error hooks for handling error outputs
  • SHOULD implement hooks for common status responses
  • SHOULD implement contextual output as a hook
  • SHOULD make handling errors less unwieldy, need to add a logger to see them, need to create custom outputs, needs to setup html template with correct name
  • SHOULD when both query decoder and body decoder is configured, should be easier to protect against CSRF posts with all query params
  • SHOULD have type for OnErrorRender function signature
  • SHOULD not overwrite content-type header if it is already set by the implementation explicitely, for example if it writes pdf.
  • SHOULD make it clear in docs or with an error that the order of hooks is important, if one calls "writeHeader" the others won't be able to change the header
  • SHOULD have a clearer error when here is no html template defined for "error"
  • SHOULD in general, make it easier to render some response with just a status code and a simple body (no encoding)
  • SHOULD also call head hooks when not using render (but just resp.Write())
  • SHOULD have a default OnErrorRender that logs it to stderr
  • SHOULD use a single error value in the response instead of client and server, but instead: use an error type that describes it as client or server and should change the OnErrorRender signature to allow customization of that
  • SHOULD allow outputs to embed a type that will be populated with the request context
  • 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 be able to return all kinds of app errors with status code from exec
  • SHOULD also make it more ergonomic to just render a 204, 404, Conflict and other common exec status responses for REST endpoints
  • SHOULD make it ergonomic to render output with common 2xx status codes: 201, 204
  • SHOULD make it ergonomic to redirect the client
  • SHOULD make AppError fields public
  • SHOULD rename "Check" on input to "Validate", way more obvious and less suprising
  • SHOULD SkipEncode should also work when returned directly to the render
  • COULD have an hook that sets the status code based on whether the response is in a client or server error mode
  • COULD include a more composable ways for behaviour to be added to an output: what if it redirects and sets a cookie
  • COULD allow middleware to install a hook that is called just before the first byte is written to the response body for middleware that needs to write a header
  • COULD check for the user that the output in a pointer value if setContext would be called
  • COULD make withEncoding and withHooks consistent in naming (one with s, other without)
  • COULD have package level doc summary for coding package
  • COULD not get nil pointer if status created is embedded on a nil output struct. Instead, embedding should trigger behaviour differently
  • COULD use the configuration pattern as described here: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
  • 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
  • COULD assert status codes send to Error, Errorf to be in range of 400-600
  • COULD support something like this: https://github.com/mozillazg/go-httpheader on output structs
  • COULD encode response status also from output struct tags: maybe use AWS SDK approach of tagging with 'location:"header/uri/body"'
  • 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
  • WONT add more logging methods to the logger to track, logging was not really used at all

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Codec added in v0.1.1

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

Codec provides http.Handlers that automatically decode requests and encode responses based on input and output structs

func New

func New(opts ...Option) (c *Codec)

New initiates a new ep Codec

func (*Codec) Handle added in v0.1.1

func (c *Codec) Handle(f interface{}) http.Handler

Handle will initiate an http handler that handles request according to the Codec configuration.

type Error added in v0.0.7

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

func Err added in v0.1.0

func Err(args ...interface{}) *Error

func (*Error) Error added in v0.1.0

func (e *Error) Error() string

func (*Error) Is added in v0.1.0

func (e *Error) Is(target error) bool

func (*Error) Unwrap added in v0.1.0

func (e *Error) Unwrap() error

type ErrorHook added in v0.1.0

type ErrorHook func(err error) (out interface{})

ErrorHook can be provided as an option to be called whenever an error is about to be rendered. The error can be logged or an output type can be returend to customize how the error will be turned into a response.

Multiple error hooks can be configured and the first that returns a non-nil output takes precedence.

The returned output will be subjected to the same hooks that any other output would be.

type ErrorKind added in v0.1.0

type ErrorKind uint8
const (
	OtherError        ErrorKind = iota
	ServerError                 // unexpected server condition
	UnacceptableError           // no encoder supports what the client accepts
	UnsupportedError            // no decoder supports the content type sent by the client
	RequestHookError            // request hook failed to run
	DecoderError                // decoder failed while decoding
	EncoderError                // encoder failed while encoding
)

type Op added in v0.1.0

type Op string

type Option added in v0.1.0

type Option interface {
	// contains filtered or unexported methods
}

Option configures the codec

func Options added in v0.1.0

func Options(opts ...Option) Option

func RequestDecoding added in v0.1.0

func RequestDecoding(dec epcoding.Decoding) Option

RequestDecoding option adds an additional supported request decoding for this Codec

func ResponseEncoding added in v0.1.0

func ResponseEncoding(enc epcoding.Encoding) Option

ResponseEncoding option adds an additional supported response encoding for this Codec

type PeekReadCloser added in v0.1.0

type PeekReadCloser interface {
	io.ReadCloser
	Peek(n int) ([]byte, error)
}

PeekReadCloser allows for reading, closing and peeking

func Buffer added in v0.1.0

func Buffer(rc io.ReadCloser) PeekReadCloser

Buffer the provided ReadCloser so that it is possible to peek into the reader without influencing the next read. Unlike the original ReadCloser this buffered variant might not error immediately when calling Read after Close. Instead it will error once the buffered bytes are completely read.

type RequestHook added in v0.1.0

type RequestHook func(r *http.Request, in interface{}) error

RequestHook option allows reading arbitrary properties on the request to decorate the input value before the request body is decoded in the bind.

If an error is returned the bind call will return false and the error will rendered.

type ResponseHook added in v0.1.0

type ResponseHook func(w http.ResponseWriter, r *http.Request, out interface{})

ResponseHook option provides arbitrary modification to the response header just before is send for the response. It is provided with the output that is currently rendered but if the response is called without using the render method this argument might be nil.

type ResponseWriter added in v0.1.0

type ResponseWriter interface {
	Bind(in interface{}) bool
	Render(outs ...interface{})
	Recover()
	http.ResponseWriter
}

ResponseWriter extends the traditional http.ResponseWriter interface with functionality that standardizes input decoding and output enepcoding.

func NewResponse

func NewResponse(
	w http.ResponseWriter,
	r *http.Request,
	reqh []RequestHook,
	resh []ResponseHook,
	errh []ErrorHook,
	decs []epcoding.Decoding,
	encs []epcoding.Encoding,
) ResponseWriter

NewResponse initializes a ResponseWriter

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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