render

package module
v1.1.3 Latest Latest
Warning

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

Go to latest
Published: Feb 3, 2021 License: MIT Imports: 15 Imported by: 0

README

render

The render package helps manage HTTP request / response payloads.

Every well-designed, robust and maintainable Web Service / REST API also needs well-defined request and response payloads. Together with the endpoint handlers, the request and response payloads make up the contract between your server and the clients calling on it.

Typically, in a REST API application, you will have your data models (objects/structs) that hold lower-level runtime application state, and at times you need to assemble, decorate, hide or transform the representation before responding to a client. That server output (response payload) structure, is also likely the input structure to another handler on the server.

This is where render comes in - offering a few simple helpers and interfaces to provide a simple pattern for managing payload encoding and decoding.

We've also combined it with some helpers for responding to content types and parsing request bodies. Please have a look at the rest example which uses the latest gdey/chi-render sub-pkg.

All feedback is welcome, thank you!

Documentation

Overview

The render package helps manage HTTP request and response payloads.

Every well-designed, robust and maintainable Web Service / REST API also needs well-defined request and payloads. Together with the endpoint handler, the request and response payloads make up the contract between your server and the clients calling on it.

Typically in a REST API application, you will have data models (objects/structs) that hold lower-level runtime application state, and at time you need to assemble, decorate hide or transform the representation before responding to a client. That server output (response payload) structure, is likely the input structure to another handler on the server.

This is where render comes in - offering a few simple helpers and to provide a simple pattern for managing payload encoding and decoding.

The typical flow will look like the following:

  +-------------+
  | REQUEST     | // The in coming request from the client
  +-----+-------+
        |
        V
  +-------------+ // Determined by the Content type of the body
  | decoders    | // in order to decode the body into the passed
  +-----+-------+ // into the provided object/struct (decoders package)
        |
        V
  +-------------+ // Modify, assemble, decorate based models off the
  | Binder      | // decoded object/struct from the decoder
  +-----+-------+
        |
        V
  +-------------+
  | Application |
  +-----+-------+
        |
        V
  +-------------+ // Modify, assemble, decorate  models to prepare
  | Render      | // them to be encoded by the Responder
  +-----+-------+
        |
        V
  +-------------+ // Determined by the Content-Type of the response
  | responders  | // object, encode the provided object/struct (responders package)
  +-----+-------+
        |
        V
  +-------------+
  | RESPONSE    |
  +-------------+

Index

Constants

View Source
const (
	ContentTypeNone        = ContentType("")
	ContentTypeDefault     = ContentType("*/*")
	ContentTypeJSON        = ContentType("application/json")
	ContentTypeData        = ContentType("application/octet-stream")
	ContentTypeForm        = ContentType("multipart/form-data")
	ContentTypeEventStream = ContentType("text/event-stream")
	ContentTypeHTML        = ContentType("text/html")
	ContentTypePlainText   = ContentType("text/plain")
	ContentTypeXML         = ContentType("text/xml")
)

ContentTypes that are commonly used

Variables

View Source
var (
	// ErrorHeaderPrefix is the prefix to add to the http headers for ErrResponse objects
	//
	// The following headers are created:
	//    * ${ErrorHeaderPrefix}error-status
	//    * ${ErrorHeaderPrefix}error-code
	//    * ${ErrorHeaderPrefix}error-text
	//
	ErrorHeaderPrefix = "chi-render-"

	// GenErrorPin will generate a random 6 digit number that will be used to identify
	// the message in logs. Replace this if you want to change the way the error code
	// is generated
	GenErrorPin = func() string {
		var pin [errorCodeLength]byte

		_, _ = rand.Read(pin[:])
		for i := range pin {

			pin[i] = (pin[i] % 10) + '0'
		}
		return string(pin[:])
	}
	// ErrorLogTo is the default error logging function.
	//
	// If you want all your ErrResponse based errors to log when
	// they are render be sure to set this variable. Once can easily
	// set it in an Init function:
	//
	// e.g.
	//
	//    func init(){
	//       render.ErrorHeaderPrefix = "my-prefix-"
	//       render.ErrorLogTo = render.ErrLogToStdOut
	//    }
	//
	ErrorLogTo func(*ErrResponse)
)
View Source
var (
	ContentTypeCtxKey = helpers.ContentTypeCtxKey
)
View Source
var (
	// ErrControllerIsNil will be returned by methods that require the Controller object
	// to be not nil
	ErrControllerIsNil = errors.New("controller is nil")
)

Functions

func AllowedContentTypes added in v1.1.0

func AllowedContentTypes(contentTypes ContentTypeSet) func(next http.Handler) http.Handler

func Bind

func Bind(r *http.Request, v Binder) error

Bind decodes a request body and executes the Binder method of the payload structure.

func ChannelEventStream added in v1.1.0

func ChannelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) error

func ErrLogToStdOut added in v1.1.1

func ErrLogToStdOut(err *ErrResponse)

ErrLogToStdOut can be used to use go log to log out the error when it is rendered

func Render

func Render(w http.ResponseWriter, r *http.Request, v Renderer) error

Render renders a single payload and respond to the client request.

func RenderList

func RenderList(w http.ResponseWriter, r *http.Request, l []Renderer) error

RenderList renders a slice of payloads and responds to the client request.

func SetContentType

func SetContentType(contentType ContentType) func(next http.Handler) http.Handler

SetContentType is a middleware that forces response Content-Type.

func SetDecoder added in v1.1.0

func SetDecoder(contentType ContentType, decoder decoders.Func)

SetDecoder will set the decoder for the given content type. Use a nil DecodeFunc to unset a content type

func SetResponder added in v1.1.0

func SetResponder(contentType ContentType, responder responders.Func)

SetResponder will set the responder for the given content type. Use a nil RespondFunc to unset a content type

func Status

func Status(r *http.Request, status int)

Status sets a HTTP response status code hint into request context at any point during the request life-cycle. Before the Responder sends its response header it will check the StatusCtxKey

func WithCtx added in v1.1.0

func WithCtx(c *Controller) func(http.Handler) http.Handler

WithCtx is the middleware to attach a new render.Controller to the context

Types

type Binder

type Binder interface {
	// Binder should be used to recompose the original the data model object.
	// The Binder function is called after the decoders is called so the body
	// of the http.Request object will be spent.
	Bind(r *http.Request) error
}

Binder interface for managing request payloads.

type ContentType

type ContentType string

ContentType is an enumeration of common HTTP content types.

func ContentTypeFromString added in v1.1.0

func ContentTypeFromString(mediaType string) (ContentType, error)

ContentTypeFromString will call mime.ParseMediaType to get the content type out

func GetContentType

func GetContentType(str string) (ContentType, error)

GetContentType returns the base mimetype from the string. This uses mime.ParseMediaType to actually parse the string.

func GetRequestContentType

func GetRequestContentType(r *http.Request, dflt ContentType) ContentType

GetRequestContentType is a helper function that returns ContentType based on context or "content-Type" request header.

func (ContentType) Is added in v1.1.0

func (contentType ContentType) Is(mimeType string) bool

Is the content type a match for the given mime type

func (ContentType) String added in v1.1.0

func (contentType ContentType) String() string

type ContentTypeSet added in v1.1.0

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

ContentTypeSet is a ordered set of content types

func GetAcceptedContentType

func GetAcceptedContentType(r *http.Request) *ContentTypeSet

GetAcceptedContentType is a helper function that returns a set of ContentTypes based on context or "Accept" request header.

func NewContentTypeSet added in v1.1.0

func NewContentTypeSet(types ...string) *ContentTypeSet

NewContentTypeSet returns a new set of ContentTypes based on the set of strings passed in. mime.ParseMediaType is used to parse each string. Empty strings and strings that do not parse are ignored.

func SetOfContentTypes added in v1.1.0

func SetOfContentTypes(types ...ContentType) *ContentTypeSet

SetOfContentTypes returns a set of the given ContentTypes

func SupportedDecoders added in v1.1.0

func SupportedDecoders() *ContentTypeSet

SupportedDecoders returns a ContentTypeSet of the configured Content types with decoders

func SupportedResponders added in v1.1.0

func SupportedResponders() *ContentTypeSet

SupportedResponders returns a ContentTypeSet of the configured Content types with responders

func (*ContentTypeSet) Has added in v1.1.0

func (set *ContentTypeSet) Has(contentType ContentType) bool

Has checks to see if the set contains the content type

func (*ContentTypeSet) Next added in v1.1.0

func (set *ContentTypeSet) Next() bool

Next returns if there is another content type waiting, and if there is advance to it

func (*ContentTypeSet) Reset added in v1.1.0

func (set *ContentTypeSet) Reset()

Reset to the start of the content types

func (*ContentTypeSet) String added in v1.1.0

func (set *ContentTypeSet) String() string

func (*ContentTypeSet) StringHas added in v1.1.0

func (set *ContentTypeSet) StringHas(mediaType string) bool

StringHas is like Has but first parses the contentType out if the mediaType using mime.ParseMediaType; parse errors return false

func (*ContentTypeSet) Type added in v1.1.0

func (set *ContentTypeSet) Type() ContentType

Type returns the current ContentType of the set

func (*ContentTypeSet) Types added in v1.1.0

func (set *ContentTypeSet) Types() (types []ContentType)

Types returns a copy of the content types in order specified

type Controller added in v1.1.0

type Controller struct {

	// If no content type matches, this content type will be used.
	DefaultRequest ContentType
	// If no Accept header match, this content type will be used to render the object
	DefaultResponse ContentType
	// contains filtered or unexported fields
}

Controller is responsible for managing the respond types that are available

func CloneDefault added in v1.1.0

func CloneDefault() *Controller

CloneDefault will return a Clone of the default controller

func FromContext added in v1.1.0

func FromContext(r *http.Request) *Controller

FromContext will retrieve the render object from the context

func (*Controller) Bind added in v1.1.0

func (ctrl *Controller) Bind(r *http.Request, v Binder) error

Bind decodes a request body and executes the Binder method of the payload structure.

func (*Controller) Clone added in v1.1.0

func (ctrl *Controller) Clone() *Controller

Clone will return a deep copy version of the controller if ctrl is nil a clone of the default system controller will be returned instead

func (*Controller) Render added in v1.1.0

func (ctrl *Controller) Render(w http.ResponseWriter, r *http.Request, v Renderer) error

Render renders a single payload and respond to the client request.

func (*Controller) RenderList added in v1.1.0

func (ctrl *Controller) RenderList(w http.ResponseWriter, r *http.Request, l []Renderer) error

RenderList renders a slice of payloads and responds to the client request.

func (*Controller) SetDecoder added in v1.1.0

func (ctrl *Controller) SetDecoder(contentType ContentType, decoder decoders.Func) error

SetDecoder will set the decoder for the given content type. Use a nil DecodeFunc to unset a content type Only error this function will return is ErrControllerIsNil; is returned if the Controller object is nil.

func (*Controller) SetResponder added in v1.1.0

func (ctrl *Controller) SetResponder(contentType ContentType, responder responders.Func) error

SetResponder will set the responder for the given content type. Use a nil RespondFunc to unset a content type Only error this function will return is ErrControllerIsNil; is returned if the Controller object is nil.

func (*Controller) Status added in v1.1.0

func (ctrl *Controller) Status(r *http.Request, status int)

Status sets a HTTP response status code hint into request context at any point during the request life-cycle. Before the Responder sends its response header it will check the StatusCtxKey

func (*Controller) SupportedDecoders added in v1.1.0

func (ctrl *Controller) SupportedDecoders() *ContentTypeSet

SupportedDecoders returns a ContentTypeSet of the configured Content types with decoders

func (*Controller) SupportedResponders added in v1.1.0

func (ctrl *Controller) SupportedResponders() *ContentTypeSet

SupportedResponders returns a ContentTypeSet of the configured Content types with responders

type ErrResponse added in v1.1.1

type ErrResponse struct {
	Err        error  `json:"-"`               // low-level runtime error
	StatusCode int    `json:"-"`               // http response status code
	StatusText string `json:"status"`          // user-level status message
	ErrorCode  string `json:"code"`            // application-specific error code
	ErrorText  string `json:"error,omitempty"` // application-level error message, for debugging
	// If you want to print out the issue set this the default ErrLogTo
	LogTo func(*ErrResponse) `json:"-"`
}

ErrResponse renderer type for handling all sorts of errors.

In the best case scenario, the excellent github.com/pkg/errors package helps reveal information on the error, setting it on Err, and in the Render() method, using it to set the application-specific error code in AppCode.

func (*ErrResponse) Render added in v1.1.1

func (err *ErrResponse) Render(w http.ResponseWriter, r *http.Request) error

Render will be called by the render to modify the ErrResponse object before it gets encoded by the Responders

type Interface added in v1.1.0

type Interface interface {
	Bind(r *http.Request, v Binder) error
	Render(w http.ResponseWriter, r *http.Request, v Renderer) error
	RenderList(w http.ResponseWriter, r *http.Request, l []Renderer) error
}

Interface defines what a render controller should behave like

type NilBinder added in v1.1.1

type NilBinder struct{}

NilBinder is an empty struct that can be embedded to provide a simple way to return a struct into a Bind-able object

func (NilBinder) Bind added in v1.1.1

func (NilBinder) Bind(_ *http.Request) error

Bind does nothing

type NilRender added in v1.1.1

type NilRender struct{}

NilRender is an empty struct that can be embedded to provide a simple way to turn a struct into a Render-able object

func (NilRender) Render added in v1.1.1

Render does nothing

type Renderer

type Renderer interface {
	// Render should modify the object so that it is in the correct configuration
	// for the responders to render the object. One can interrogate the request object
	// or if necessary modify the headers in the ResponseWriter object.
	// The Render method should not write to the body fo the ResponseWriter object,
	// the at is reserved for the responder objects.
	Render(w http.ResponseWriter, r *http.Request) error
}

Renderer interface for managing response payloads.

Directories

Path Synopsis
_examples
blog
BLOG ==== This example demonstrates a HTTP REST web service with some fixture data.
BLOG ==== This example demonstrates a HTTP REST web service with some fixture data.

Jump to

Keyboard shortcuts

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