context

package
v0.0.0-...-0a1b186 Latest Latest
Warning

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

Go to latest
Published: Aug 9, 2017 License: BSD-3-Clause Imports: 29 Imported by: 32

Documentation

Index

Constants

View Source
const (

	// NoWritten !=-1 => when nothing written before
	NoWritten = -1
	// StatusCodeWritten != 0 =>  when only status code written
	StatusCodeWritten = 0
)
View Source
const (
	// NoLayout to disable layout for a particular template file
	NoLayout = "ion.nolayout"
)

Variables

View Source
var ErrPushNotSupported = errors.New("push feature is not supported by this ResponseWriter")

ErrPushNotSupported is returned by the Push method to indicate that HTTP/2 Push support is not available.

View Source
var LimitRequestBodySize = func(maxRequestBodySizeBytes int64) Handler {
	return func(ctx Context) {
		ctx.SetMaxRequestBodySize(maxRequestBodySizeBytes)
		ctx.Next()
	}
}

LimitRequestBodySize is a middleware which sets a request body size limit for all next handlers in the chain.

View Source
var Recorder = func(ctx Context) {
	ctx.Record()
	ctx.Next()
}

Recorder the middleware to enable response writer recording ( ResponseWriter -> ResponseRecorder)

View Source
var RequestTransactionScope = TransactionScopeFunc(func(maybeErr TransactionErrResult, ctx Context) bool {
	if maybeErr.IsFailure() {

		ctx.ResponseWriter().SetBeforeFlush(func() {

			w := ctx.ResponseWriter().(*ResponseRecorder)
			if maybeErr.Reason != "" {

				w.SetBodyString(maybeErr.Reason)
				w.WriteHeader(maybeErr.StatusCode)
				ctx.ContentType(maybeErr.ContentType)
			} else {

				ctx.StatusCode(maybeErr.StatusCode)
				ctx.StopExecution()
			}
		})

		return false
	}

	return true
})

RequestTransactionScope explanation:

if scope fails (if transaction.IsFailure() == true) then the rest of the context's response (transaction or normal flow) is not written to the client, and an error status code is written instead.

View Source
var (
	// SetCookieKVExpiration is 2 hours by-default
	// you can change it or simple, use the SetCookie for more control.
	SetCookieKVExpiration = time.Duration(120) * time.Minute
)
View Source
var (
	// StaticCacheDuration expiration duration for INACTIVE file handlers, it's the only one global configuration
	// which can be changed.
	StaticCacheDuration = 20 * time.Second
)
View Source
var TransientTransactionScope = TransactionScopeFunc(func(maybeErr TransactionErrResult, ctx Context) bool {
	if maybeErr.IsFailure() {
		ctx.Recorder().Reset()
	}
	return true
})

TransientTransactionScope explanation:

independent 'silent' scope, if transaction fails (if transaction.IsFailure() == true) then its response is not written to the real context no error is provided to the user. useful for the most cases.

Functions

func DecodeQuery

func DecodeQuery(path string) string

DecodeQuery returns the uri parameter as url (string) useful when you want to pass something to a database and be valid to retrieve it via context.Param use it only for special cases, when the default behavior doesn't suits you.

http://www.blooberry.com/indexdot/html/topics/urlencoding.htm it uses just the url.QueryUnescape

func DecodeURL

func DecodeURL(uri string) string

DecodeURL returns the decoded uri useful when you want to pass something to a database and be valid to retrieve it via context.Param use it only for special cases, when the default behavior doesn't suits you.

http://www.blooberry.com/indexdot/html/topics/urlencoding.htm it uses just the url.Parse

func Next

func Next(ctx Context)

Next calls all the next handler from the handlers chain, it should be used inside a middleware.

func WriteJSON

func WriteJSON(writer io.Writer, v interface{}, options JSON) (int, error)

WriteJSON marshals the given interface object and writes the JSON response to the 'writer'. Ignores StatusCode, Gzip, StreamingJSON options.

func WriteJSONP

func WriteJSONP(writer io.Writer, v interface{}, options JSONP) (int, error)

WriteJSONP marshals the given interface object and writes the JSON response to the writer.

func WriteMarkdown

func WriteMarkdown(writer io.Writer, markdownB []byte, options Markdown) (int, error)

WriteMarkdown parses the markdown to html and renders these contents to the writer.

func WriteXML

func WriteXML(writer io.Writer, v interface{}, options XML) (int, error)

WriteXML marshals the given interface object and writes the XML response to the writer.

Types

type Application

type Application interface {
	// ConfigurationReadOnly returns all the available configuration values can be used on a request.
	ConfigurationReadOnly() ConfigurationReadOnly

	// Logger returns the logrus logger instance(pointer) that is being used inside the "app".
	Logger() *logrus.Logger

	// View executes and write the result of a template file to the writer.
	//
	// Use context.View to render templates to the client instead.
	// Returns an error on failure, otherwise nil.
	View(writer io.Writer, filename string, layout string, bindingData interface{}) error

	// ServeHTTPC is the internal router, it's visible because it can be used for advanced use cases,
	// i.e: routing within a foreign context.
	//
	// It is ready to use after Build state.
	ServeHTTPC(ctx Context)

	// ServeHTTP is the main router handler which calls the .Serve and acquires a new context from the pool.
	//
	// It is ready to use after Build state.
	ServeHTTP(w http.ResponseWriter, r *http.Request)

	// FireErrorCode executes an error http status code handler
	// based on the context's status code.
	//
	// If a handler is not already registered,
	// then it creates & registers a new trivial handler on the-fly.
	FireErrorCode(ctx Context)
}

Application is the context's owner. This interface contains the functions that can be used with safety inside a Handler by `context.Application()`.

type BodyDecoder

type BodyDecoder interface {
	Decode(data []byte) error
}

BodyDecoder is an interface which any struct can implement in order to customize the decode action from ReadJSON and ReadXML

Trivial example of this could be: type User struct { Username string }

func (u *User) Decode(data []byte) error {
	  return json.Unmarshal(data, u)
}

the 'context.ReadJSON/ReadXML(&User{})' will call the User's Decode option to decode the request body

Note: This is totally optionally, the default decoders for ReadJSON is the encoding/json and for ReadXML is the encoding/xml.

type ConfigurationReadOnly

type ConfigurationReadOnly interface {
	// GetVHost returns the non-exported vhost config field.
	//
	// If original addr ended with :443 or :80, it will return the host without the port.
	// If original addr was :https or :http, it will return localhost.
	// If original addr was 0.0.0.0, it will return localhost.
	GetVHost() string

	// GetDisablePathCorrection returns the configuration.DisablePathCorrection,
	// DisablePathCorrection corrects and redirects the requested path to the registered path
	// for example, if /home/ path is requested but no handler for this Route found,
	// then the Router checks if /home handler exists, if yes,
	// (permant)redirects the client to the correct path /home.
	GetDisablePathCorrection() bool

	// GetEnablePathEscape is the configuration.EnablePathEscape,
	// returns true when its escapes the path, the named parameters (if any).
	GetEnablePathEscape() bool

	// GetFireMethodNotAllowed returns the configuration.FireMethodNotAllowed.
	GetFireMethodNotAllowed() bool
	// GetDisableBodyConsumptionOnUnmarshal returns the configuration.GetDisableBodyConsumptionOnUnmarshal,
	// manages the reading behavior of the context's body readers/binders.
	// If returns true then the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`
	// is disabled.
	//
	// By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
	// if this field setted to true then a new buffer will be created to read from and the request body.
	// The body will not be changed and existing data before the
	// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
	GetDisableBodyConsumptionOnUnmarshal() bool

	// GetDisableAutoFireStatusCode returns the configuration.DisableAutoFireStatusCode.
	// Returns true when the http error status code handler automatic execution turned off.
	GetDisableAutoFireStatusCode() bool

	// GetTimeFormat returns the configuration.TimeFormat,
	// format for any kind of datetime parsing.
	GetTimeFormat() string

	// GetCharset returns the configuration.Charset,
	// the character encoding for various rendering
	// used for templates and the rest of the responses.
	GetCharset() string

	// GetTranslateLanguageContextKey returns the configuration's TranslateFunctionContextKey value,
	// used for i18n.
	GetTranslateFunctionContextKey() string

	// GetTranslateLanguageContextKey returns the configuration's TranslateLanguageContextKey value,
	// used for i18n.
	GetTranslateLanguageContextKey() string

	// GetViewLayoutContextKey returns the key of the context's user values' key
	// which is being used to set the template
	// layout from a middleware or the main handler.
	// Overrides the parent's or the configuration's.
	GetViewLayoutContextKey() string
	// GetViewDataContextKey returns the key of the context's user values' key
	// which is being used to set the template
	// binding data from a middleware or the main handler.
	GetViewDataContextKey() string

	// GetRemoteAddrHeaders returns the allowed request headers names
	// that can be valid to parse the client's IP based on.
	//
	// Defaults to:
	// "X-Real-Ip":             true,
	// "X-Forwarded-For":       true,
	// "CF-Connecting-IP": false
	//
	// Look `context.RemoteAddr()` for more.
	GetRemoteAddrHeaders() map[string]bool

	// GetOther returns the configuration.Other map.
	GetOther() map[string]interface{}
}

ConfigurationReadOnly can be implemented by Configuration, it's being used inside the Context. All methods that it contains should be "safe" to be called by the context at "serve time". A configuration field may be missing when it's not safe or its useless to be called from a request handler.

type Context

type Context interface {

	// BeginRequest is executing once for each request
	// it should prepare the (new or acquired from pool) context's fields for the new request.
	//
	// To follow the ion' flow, developer should:
	// 1. reset handlers to nil
	// 2. reset values to empty
	// 3. reset sessions to nil
	// 4. reset response writer to the http.ResponseWriter
	// 5. reset request to the *http.Request
	// and any other optional steps, depends on dev's application type.
	BeginRequest(http.ResponseWriter, *http.Request)
	// EndRequest is executing once after a response to the request was sent and this context is useless or released.
	//
	// To follow the ion' flow, developer should:
	// 1. flush the response writer's result
	// 2. release the response writer
	// and any other optional steps, depends on dev's application type.
	EndRequest()

	// ResponseWriter returns an http.ResponseWriter compatible response writer, as expected.
	ResponseWriter() ResponseWriter
	// ResetResponseWriter should change or upgrade the Context's ResponseWriter.
	ResetResponseWriter(ResponseWriter)

	// Request returns the original *http.Request, as expected.
	Request() *http.Request

	// Do calls the SetHandlers(handlers)
	// and executes the first handler,
	// handlers should not be empty.
	//
	// It's used by the router, developers may use that
	// to replace and execute handlers immediately.
	Do(Handlers)

	// AddHandler can add handler(s)
	// to the current request in serve-time,
	// these handlers are not persistenced to the router.
	//
	// Router is calling this function to add the route's handler.
	// If AddHandler called then the handlers will be inserted
	// to the end of the already-defined route's handler.
	//
	AddHandler(...Handler)
	// SetHandlers replaces all handlers with the new.
	SetHandlers(Handlers)
	// Handlers keeps tracking of the current handlers.
	Handlers() Handlers

	// HandlerIndex sets the current index of the
	// current context's handlers chain.
	// If -1 passed then it just returns the
	// current handler index without change the current index.rns that index, useless return value.
	//
	// Look Handlers(), Next() and StopExecution() too.
	HandlerIndex(n int) (currentIndex int)
	// HandlerName returns the current handler's name, helpful for debugging.
	HandlerName() string
	// Next calls all the next handler from the handlers chain,
	// it should be used inside a middleware.
	//
	// Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
	Next()
	// NextHandler returns(but it is NOT executes) the next handler from the handlers chain.
	//
	// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
	NextHandler() Handler
	// Skip skips/ignores the next handler from the handlers chain,
	// it should be used inside a middleware.
	Skip()
	// StopExecution if called then the following .Next calls are ignored.
	StopExecution()
	// IsStopped checks and returns true if the current position of the Context is 255,
	// means that the StopExecution() was called.
	IsStopped() bool

	// Params returns the current url's named parameters key-value storage.
	// Named path parameters are being saved here.
	// This storage, as the whole Context, is per-request lifetime.
	Params() *RequestParams

	// Values returns the current "user" storage.
	// Named path parameters and any optional data can be saved here.
	// This storage, as the whole Context, is per-request lifetime.
	//
	// You can use this function to Set and Get local values
	// that can be used to share information between handlers and middleware.
	Values() *memstore.Store
	// Translate is the i18n (localization) middleware's function,
	// it calls the Get("translate") to return the translated value.
	//
	// Example: https://github.com/get-ion/ion/tree/master/_examples/miscellaneous/i18n
	Translate(format string, args ...interface{}) string

	// Method returns the request.Method, the client's http method to the server.
	Method() string
	// Path returns the full request path,
	// escaped if EnablePathEscape config field is true.
	Path() string
	// RequestPath returns the full request path,
	// based on the 'escape'.
	RequestPath(escape bool) string

	// Host returns the host part of the current url.
	Host() string
	// Subdomain returns the subdomain of this request, if any.
	// Note that this is a fast method which does not cover all cases.
	Subdomain() (subdomain string)
	// RemoteAddr tries to parse and return the real client's request IP.
	//
	// Based on allowed headers names that can be modified from Configuration.RemoteAddrHeaders.
	//
	// If parse based on these headers fail then it will return the Request's `RemoteAddr` field
	// which is filled by the server before the HTTP handler.
	//
	// Look `Configuration.RemoteAddrHeaders`,
	//      `Configuration.WithRemoteAddrHeader(...)`,
	//      `Configuration.WithoutRemoteAddrHeader(...)` for more.
	RemoteAddr() string
	// GetHeader returns the request header's value based on its name.
	GetHeader(name string) string
	// IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
	//
	// Read more at: http://www.w3schools.com/ajax/
	IsAjax() bool

	// Header adds a header to the response writer.
	Header(name string, value string)

	// ContentType sets the response writer's header key "Content-Type" to the 'cType'.
	ContentType(cType string)
	// GetContentType returns the response writer's header value of "Content-Type"
	// which may, setted before with the 'ContentType'.
	GetContentType() string

	// StatusCode sets the status code header to the response.
	// Look .GetStatusCode too.
	StatusCode(statusCode int)
	// GetStatusCode returns the current status code of the response.
	// Look StatusCode too.
	GetStatusCode() int

	// Redirect redirect sends a redirect response the client
	// accepts 2 parameters string and an optional int
	// first parameter is the url to redirect
	// second parameter is the http status should send, default is 302 (StatusFound),
	// you can set it to 301 (Permant redirect), if that's nessecery
	Redirect(urlToRedirect string, statusHeader ...int)

	// URLParam returns the get parameter from a request , if any.
	URLParam(name string) string
	// URLParamInt returns the url query parameter as int value from a request,
	// returns an error if parse failed.
	URLParamInt(name string) (int, error)
	// URLParamInt64 returns the url query parameter as int64 value from a request,
	// returns an error if parse failed.
	URLParamInt64(name string) (int64, error)
	// URLParams returns a map of GET query parameters separated by comma if more than one
	// it returns an empty map if nothing found.
	URLParams() map[string]string

	// FormValue returns a single form value by its name/key
	FormValue(name string) string
	// FormValues returns all post data values with their keys
	// form data, get, post & put query arguments
	//
	// NOTE: A check for nil is necessary.
	FormValues() map[string][]string
	// PostValue returns a form's only-post value by its name,
	// same as Request.PostFormValue.
	PostValue(name string) string
	// FormFile returns the first file for the provided form key.
	// FormFile calls ctx.Request.ParseMultipartForm and ParseForm if necessary.
	//
	// same as Request.FormFile.
	FormFile(key string) (multipart.File, *multipart.FileHeader, error)

	// NotFound emits an error 404 to the client, using the specific custom error error handler.
	// Note that you may need to call ctx.StopExecution() if you don't want the next handlers
	// to be executed. Next handlers are being executed on ion because you can alt the
	// error code and change it to a more specific one, i.e
	// users := app.Party("/users")
	// users.Done(func(ctx context.Context){ if ctx.StatusCode() == 400 { /*  custom error code for /users */ }})
	NotFound()

	// SetMaxRequestBodySize sets a limit to the request body size
	// should be called before reading the request body from the client.
	SetMaxRequestBodySize(limitOverBytes int64)

	// UnmarshalBody reads the request's body and binds it to a value or pointer of any type
	// Examples of usage: context.ReadJSON, context.ReadXML.
	UnmarshalBody(v interface{}, unmarshaler Unmarshaler) error
	// ReadJSON reads JSON from request's body and binds it to a value of any json-valid type.
	ReadJSON(jsonObject interface{}) error
	// ReadXML reads XML from request's body and binds it to a value of any xml-valid type.
	ReadXML(xmlObject interface{}) error
	// ReadForm binds the formObject  with the form data
	// it supports any kind of struct.
	ReadForm(formObject interface{}) error

	// Write writes the data to the connection as part of an HTTP reply.
	//
	// If WriteHeader has not yet been called, Write calls
	// WriteHeader(http.StatusOK) before writing the data. If the Header
	// does not contain a Content-Type line, Write adds a Content-Type set
	// to the result of passing the initial 512 bytes of written data to
	// DetectContentType.
	//
	// Depending on the HTTP protocol version and the client, calling
	// Write or WriteHeader may prevent future reads on the
	// Request.Body. For HTTP/1.x requests, handlers should read any
	// needed request body data before writing the response. Once the
	// headers have been flushed (due to either an explicit Flusher.Flush
	// call or writing enough data to trigger a flush), the request body
	// may be unavailable. For HTTP/2 requests, the Go HTTP server permits
	// handlers to continue to read the request body while concurrently
	// writing the response. However, such behavior may not be supported
	// by all HTTP/2 clients. Handlers should read before writing if
	// possible to maximize compatibility.
	Write(body []byte) (int, error)
	// Writef formats according to a format specifier and writes to the response.
	//
	// Returns the number of bytes written and any write error encountered.
	Writef(format string, args ...interface{}) (int, error)
	// WriteString writes a simple string to the response.
	//
	// Returns the number of bytes written and any write error encountered.
	WriteString(body string) (int, error)
	// WriteWithExpiration like Write but it sends with an expiration datetime
	// which is refreshed every package-level `StaticCacheDuration` field.
	WriteWithExpiration(body []byte, modtime time.Time) (int, error)
	// StreamWriter registers the given stream writer for populating
	// response body.
	//
	// Access to context's and/or its' members is forbidden from writer.
	//
	// This function may be used in the following cases:
	//
	//     * if response body is too big (more than ion.LimitRequestBodySize(if setted)).
	//     * if response body is streamed from slow external sources.
	//     * if response body must be streamed to the client in chunks.
	//     (aka `http server push`).
	//
	// receives a function which receives the response writer
	// and returns false when it should stop writing, otherwise true in order to continue
	StreamWriter(writer func(w io.Writer) bool)

	//  +------------------------------------------------------------+
	//  | Body Writers with compression                              |
	//  +------------------------------------------------------------+
	// ClientSupportsGzip retruns true if the client supports gzip compression.
	ClientSupportsGzip() bool
	// WriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
	// returns the number of bytes written and an error ( if the client doesn' supports gzip compression)
	//
	// This function writes temporary gzip contents, the ResponseWriter is untouched.
	WriteGzip(b []byte) (int, error)
	// TryWriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
	// If client does not supprots gzip then the contents are written as they are, uncompressed.
	//
	// This function writes temporary gzip contents, the ResponseWriter is untouched.
	TryWriteGzip(b []byte) (int, error)
	// GzipResponseWriter converts the current response writer into a response writer
	// which when its .Write called it compress the data to gzip and writes them to the client.
	//
	// Can be also disabled with its .Disable and .ResetBody to rollback to the usual response writer.
	GzipResponseWriter() *GzipResponseWriter
	// Gzip enables or disables (if enabled before) the gzip response writer,if the client
	// supports gzip compression, so the following response data will
	// be sent as compressed gzip data to the client.
	Gzip(enable bool)

	// ViewLayout sets the "layout" option if and when .View
	// is being called afterwards, in the same request.
	// Useful when need to set or/and change a layout based on the previous handlers in the chain.
	//
	// Note that the 'layoutTmplFile' argument can be setted to ion.NoLayout || view.NoLayout
	// to disable the layout for a specific view render action,
	// it disables the engine's configuration's layout property.
	//
	// Look .ViewData and .View too.
	//
	// Example: https://github.com/get-ion/ion/tree/master/_examples/view/context-view-data/
	ViewLayout(layoutTmplFile string)

	// ViewData saves one or more key-value pair in order to be passed if and when .View
	// is being called afterwards, in the same request.
	// Useful when need to set or/and change template data from previous hanadlers in the chain.
	//
	// If .View's "binding" argument is not nil and it's not a type of map
	// then these data are being ignored, binding has the priority, so the main route's handler can still decide.
	// If binding is a map or context.Map then these data are being added to the view data
	// and passed to the template.
	//
	// After .View, the data are not destroyed, in order to be re-used if needed (again, in the same request as everything else),
	// to clear the view data, developers can call:
	// ctx.Set(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey(), nil)
	//
	// If 'key' is empty then the value is added as it's (struct or map) and developer is unable to add other value.
	//
	// Look .ViewLayout and .View too.
	//
	// Example: https://github.com/get-ion/ion/tree/master/_examples/view/context-view-data/
	ViewData(key string, value interface{})

	// View renders templates based on the adapted view engines.
	// First argument accepts the filename, relative to the view engine's Directory,
	// i.e: if directory is "./templates" and want to render the "./templates/users/index.html"
	// then you pass the "users/index.html" as the filename argument.
	//
	// Look: .ViewData and .ViewLayout too.
	//
	// Examples: https://github.com/get-ion/ion/tree/master/_examples/view/
	View(filename string) error

	// Binary writes out the raw bytes as binary data.
	Binary(data []byte) (int, error)
	// Text writes out a string as plain text.
	Text(text string) (int, error)
	// HTML writes out a string as text/html.
	HTML(htmlContents string) (int, error)
	// JSON marshals the given interface object and writes the JSON response.
	JSON(v interface{}, options ...JSON) (int, error)
	// JSONP marshals the given interface object and writes the JSON response.
	JSONP(v interface{}, options ...JSONP) (int, error)
	// XML marshals the given interface object and writes the XML response.
	XML(v interface{}, options ...XML) (int, error)
	// Markdown parses the markdown to html and renders to client.
	Markdown(markdownB []byte, options ...Markdown) (int, error)

	// ServeContent serves content, headers are autoset
	// receives three parameters, it's low-level function, instead you can use .ServeFile(string,bool)/SendFile(string,string)
	//
	// You can define your own "Content-Type" header also, after this function call
	// Doesn't implements resuming (by range), use ctx.SendFile instead
	ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error
	// ServeFile serves a view file, to send a file ( zip for example) to the client you should use the SendFile(serverfilename,clientfilename)
	// receives two parameters
	// filename/path (string)
	// gzipCompression (bool)
	//
	// You can define your own "Content-Type" header also, after this function call
	// This function doesn't implement resuming (by range), use ctx.SendFile instead
	//
	// Use it when you want to serve css/js/... files to the client, for bigger files and 'force-download' use the SendFile.
	ServeFile(filename string, gzipCompression bool) error
	// SendFile sends file for force-download to the client
	//
	// Use this instead of ServeFile to 'force-download' bigger files to the client.
	SendFile(filename string, destinationName string) error

	// SetCookie adds a cookie
	SetCookie(cookie *http.Cookie)
	// SetCookieKV adds a cookie, receives just a name(string) and a value(string)
	//
	// If you use this method, it expires at 2 hours
	// use ctx.SetCookie or http.SetCookie if you want to change more fields.
	SetCookieKV(name, value string)
	// GetCookie returns cookie's value by it's name
	// returns empty string if nothing was found.
	GetCookie(name string) string
	// RemoveCookie deletes a cookie by it's name.
	RemoveCookie(name string)
	// VisitAllCookies takes a visitor which loops
	// on each (request's) cookies' name and value.
	VisitAllCookies(visitor func(name string, value string))

	// MaxAge returns the "cache-control" request header's value
	// seconds as int64
	// if header not found or parse failed then it returns -1.
	MaxAge() int64

	// Record transforms the context's basic and direct responseWriter to a ResponseRecorder
	// which can be used to reset the body, reset headers, get the body,
	// get & set the status code at any time and more.
	Record()
	// Recorder returns the context's ResponseRecorder
	// if not recording then it starts recording and returns the new context's ResponseRecorder
	Recorder() *ResponseRecorder
	// IsRecording returns the response recorder and a true value
	// when the response writer is recording the status code, body, headers and so on,
	// else returns nil and false.
	IsRecording() (*ResponseRecorder, bool)

	// BeginTransaction starts a scoped transaction.
	//
	// You can search third-party articles or books on how Business Transaction works (it's quite simple, especially here).
	//
	// Note that this is unique and new
	// (=I haver never seen any other examples or code in Golang on this subject, so far, as with the most of ion features...)
	// it's not covers all paths,
	// such as databases, this should be managed by the libraries you use to make your database connection,
	// this transaction scope is only for context's response.
	// Transactions have their own middleware ecosystem also, look ion.go:UseTransaction.
	//
	// See https://github.com/get-ion/ion/tree/master/_examples/ for more
	BeginTransaction(pipe func(t *Transaction))
	// SkipTransactions if called then skip the rest of the transactions
	// or all of them if called before the first transaction
	SkipTransactions()
	// TransactionsSkipped returns true if the transactions skipped or canceled at all.
	TransactionsSkipped() bool

	// Exec calls the framewrok's ServeCtx
	// based on this context but with a changed method and path
	// like it was requested by the user, but it is not.
	//
	// Offline means that the route is registered to the ion and have all features that a normal route has
	// BUT it isn't available by browsing, its handlers executed only when other handler's context call them
	// it can validate paths, has sessions, path parameters and all.
	//
	// You can find the Route by app.Routes().Lookup("theRouteName")
	// you can set a route name as: myRoute := app.Get("/mypath", handler)("theRouteName")
	// that will set a name to the route and returns its RouteInfo instance for further usage.
	//
	// It doesn't changes the global state, if a route was "offline" it remains offline.
	//
	// app.None(...) and app.Routes().Offline(route)/.Online(route, method)
	//
	// Example: https://github.com/get-ion/ion/tree/master/_examples/routing/route-state
	//
	// User can get the response by simple using rec := ctx.Recorder(); rec.Body()/rec.StatusCode()/rec.Header().
	//
	// Context's Values and the Session are kept in order to be able to communicate via the result route.
	//
	// It's for extreme use cases, 99% of the times will never be useful for you.
	Exec(method string, path string)

	// Application returns the ion app instance which belongs to this context.
	// Worth to notice that this function returns an interface
	// of the Application, which contains methods that are safe
	// to be executed at serve-time. The full app's fields
	// and methods are not available here for the developer's safety.
	Application() Application

	// Deadline returns the time when work done on behalf of this context
	// should be canceled.  Deadline returns ok==false when no deadline is
	// set.  Successive calls to Deadline return the same results.
	Deadline() (deadline time.Time, ok bool)

	// Done returns a channel that's closed when work done on behalf of this
	// context should be canceled.  Done may return nil if this context can
	// never be canceled.  Successive calls to Done return the same value.
	//
	// WithCancel arranges for Done to be closed when cancel is called;
	// WithDeadline arranges for Done to be closed when the deadline
	// expires; WithTimeout arranges for Done to be closed when the timeout
	// elapses.
	//
	// Done is provided for use in select statements:
	//
	//  // Stream generates values with DoSomething and sends them to out
	//  // until DoSomething returns an error or ctx.Done is closed.
	//  func Stream(ctx context.Context, out chan<- Value) error {
	//  	for {
	//  		v, err := DoSomething(ctx)
	//  		if err != nil {
	//  			return err
	//  		}
	//  		select {
	//  		case <-ctx.Done():
	//  			return ctx.Err()
	//  		case out <- v:
	//  		}
	//  	}
	//  }
	//
	// See http://blog.golang.org/pipelines for more examples of how to use
	// a Done channel for cancelation.
	Done() <-chan struct{}

	// Err returns a non-nil error value after Done is closed.  Err returns
	// Canceled if the context was canceled or DeadlineExceeded if the
	// context's deadline passed.  No other values for Err are defined.
	// After Done is closed, successive calls to Err return the same value.
	Err() error

	// Value returns the value associated with this context for key, or nil
	// if no value is associated with key.  Successive calls to Value with
	// the same key returns the same result.
	//
	// Use context values only for request-scoped data that transits
	// processes and API boundaries, not for passing optional parameters to
	// functions.
	//
	// A key identifies a specific value in a Context.  Functions that wish
	// to store values in Context typically allocate a key in a global
	// variable then use that key as the argument to context.WithValue and
	// Context.Value.  A key can be any type that supports equality;
	// packages should define keys as an unexported type to avoid
	// collisions.
	//
	// Packages that define a Context key should provide type-safe accessors
	// for the values stores using that key:
	//
	// 	// Package user defines a User type that's stored in Contexts.
	// 	package user
	//
	// 	import "golang.org/x/net/context"
	//
	// 	// User is the type of value stored in the Contexts.
	// 	type User struct {...}
	//
	// 	// key is an unexported type for keys defined in this package.
	// 	// This prevents collisions with keys defined in other packages.
	// 	type key int
	//
	// 	// userKey is the key for user.User values in Contexts.  It is
	// 	// unexported; clients use user.NewContext and user.FromContext
	// 	// instead of using this key directly.
	// 	var userKey key = 0
	//
	// 	// NewContext returns a new Context that carries value u.
	// 	func NewContext(ctx context.Context, u *User) context.Context {
	// 		return context.WithValue(ctx, userKey, u)
	// 	}
	//
	// 	// FromContext returns the User value stored in ctx, if any.
	// 	func FromContext(ctx context.Context) (*User, bool) {
	// 		u, ok := ctx.Value(userKey).(*User)
	// 		return u, ok
	// 	}
	Value(key interface{}) interface{}
}

Context is the midle-man server's "object" for the clients.

A New context is being acquired from a sync.Pool on each connection. The Context is the most important thing on the ion's http flow.

Developers send responses to the client's request through a Context. Developers get request information from the client's request a Context.

This context is an implementation of the context.Context sub-package. context.Context is very extensible and developers can override its methods if that is actually needed.

func NewContext

func NewContext(app Application) Context

NewContext returns the default, internal, context implementation. You may use this function to embed the default context implementation to a custom one.

This context is received by the context pool.

type GzipResponseWriter

type GzipResponseWriter struct {
	ResponseWriter
	// contains filtered or unexported fields
}

GzipResponseWriter is an upgraded response writer which writes compressed data to the underline ResponseWriter.

It's a separate response writer because ion gives you the ability to "fallback" and "roll-back" the gzip encoding if something went wrong with the response, and write http errors in plain form instead.

func AcquireGzipResponseWriter

func AcquireGzipResponseWriter() *GzipResponseWriter

AcquireGzipResponseWriter returns a new *GzipResponseWriter from the pool. Releasing is done automatically when request and response is done.

func (*GzipResponseWriter) BeginGzipResponse

func (w *GzipResponseWriter) BeginGzipResponse(underline ResponseWriter)

BeginGzipResponse accepts a ResponseWriter and prepares the new gzip response writer. It's being called per-handler, when caller decide to change the response writer type.

func (*GzipResponseWriter) Disable

func (w *GzipResponseWriter) Disable()

Disable turns off the gzip compression for the next .Write's data, if called then the contents are being written in plain form.

func (*GzipResponseWriter) EndResponse

func (w *GzipResponseWriter) EndResponse()

EndResponse called right before the contents of this response writer are flushed to the client.

func (*GzipResponseWriter) FlushResponse

func (w *GzipResponseWriter) FlushResponse()

FlushResponse validates the response headers in order to be compatible with the gzip written data and writes the data to the underline ResponseWriter.

func (*GzipResponseWriter) ResetBody

func (w *GzipResponseWriter) ResetBody()

ResetBody resets the response body.

func (*GzipResponseWriter) Write

func (w *GzipResponseWriter) Write(contents []byte) (int, error)

Write compresses and writes that data to the underline response writer

type Handler

type Handler func(Context)

A Handler responds to an HTTP request. It writes reply headers and data to the Context.ResponseWriter() and then return. Returning signals that the request is finished; it is not valid to use the Context after or concurrently with the completion of the Handler call.

Depending on the HTTP client software, HTTP protocol version, and any intermediaries between the client and the ion server, it may not be possible to read from the Context.Request().Body after writing to the context.ResponseWriter(). Cautious handlers should read the Context.Request().Body first, and then reply.

Except for reading the body, handlers should not modify the provided Context.

If Handler panics, the server (the caller of Handler) assumes that the effect of the panic was isolated to the active request. It recovers the panic, logs a stack trace to the server error log, and hangs up the connection.

type Handlers

type Handlers []Handler

Handlers is just a type of slice of []Handler.

See `Handler` for more.

type JSON

type JSON struct {
	// http-specific
	StreamingJSON bool
	// content-specific
	UnescapeHTML bool
	Indent       string
	Prefix       string
}

JSON contains the options for the JSON (Context's) Renderer.

type JSONP

type JSONP struct {
	// content-specific
	Indent   string
	Callback string
}

JSONP contains the options for the JSONP (Context's) Renderer.

type Map

type Map map[string]interface{}

Map is just a shortcut of the map[string]interface{}.

type Markdown

type Markdown struct {
	// content-specific
	Sanitize bool
}

Markdown contains the options for the Markdown (Context's) Renderer.

type Pool

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

Pool is the context pool, it's used inside router and the framework by itself.

It's the only one real implementation inside this package because it used widely.

func New

func New(newFunc func() Context) *Pool

New creates and returns a new context pool.

func (*Pool) Acquire

func (c *Pool) Acquire(w http.ResponseWriter, r *http.Request) Context

Acquire returns a Context from pool. See Release.

func (*Pool) Attach

func (c *Pool) Attach(newFunc func() Context)

Attach changes the pool's return value Context.

func (*Pool) Release

func (c *Pool) Release(ctx Context)

Release puts a Context back to its pull, this function releases its resources. See Acquire.

type RequestParams

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

RequestParams is a key string - value string storage which context's request params should implement. RequestValues is for communication between middleware, RequestParams cannot be changed, are setted at the routing time, stores the dynamic named parameters, can be empty if the route is static.

func (RequestParams) Get

func (r RequestParams) Get(key string) string

Get returns a path parameter's value based on its route's dynamic path key.

func (RequestParams) GetDecoded

func (r RequestParams) GetDecoded(key string) string

GetDecoded returns the url-query-decoded user's value based on its key.

func (RequestParams) GetInt

func (r RequestParams) GetInt(key string) (int, error)

GetInt returns the param's value as int, based on its key.

func (RequestParams) GetInt64

func (r RequestParams) GetInt64(key string) (int64, error)

GetInt64 returns the user's value as int64, based on its key.

func (RequestParams) GetIntUnslashed

func (r RequestParams) GetIntUnslashed(key string) (int, error)

GetIntUnslashed same as Get but it removes the first slash if found. Usage: Get an id from a wildcard path.

Returns -1 with an error if the parameter couldn't be found.

func (RequestParams) Len

func (r RequestParams) Len() int

Len returns the full length of the parameters.

func (*RequestParams) Set

func (r *RequestParams) Set(key, value string)

Set shouldn't be used as a local storage, context's values store is the local storage, not params.

func (*RequestParams) Visit

func (r *RequestParams) Visit(visitor func(key string, value string))

Visit accepts a visitor which will be filled by the key-value params.

type ResponseRecorder

type ResponseRecorder struct {
	ResponseWriter
	// contains filtered or unexported fields
}

A ResponseRecorder is used mostly by context's transactions in order to record and change if needed the body, status code and headers.

Developers are not limited to manually ask to record a response. To turn on the recorder from a Handler, rec := context.Recorder()

func AcquireResponseRecorder

func AcquireResponseRecorder() *ResponseRecorder

AcquireResponseRecorder returns a new *AcquireResponseRecorder from the pool. Releasing is done automatically when request and response is done.

func (*ResponseRecorder) BeginRecord

func (w *ResponseRecorder) BeginRecord(underline ResponseWriter)

BeginRecord accepts its parent ResponseWriter and prepares itself, the response recorder, to record and send response to the client.

func (*ResponseRecorder) Body

func (w *ResponseRecorder) Body() []byte

Body returns the body tracked from the writer so far do not use this for edit.

func (*ResponseRecorder) ClearHeaders

func (w *ResponseRecorder) ClearHeaders()

ClearHeaders clears all headers, both temp and underline's response writer.

func (*ResponseRecorder) Clone

func (w *ResponseRecorder) Clone() ResponseWriter

Clone returns a clone of this response writer it copies the header, status code, headers and the beforeFlush finally returns a new ResponseRecorder

func (*ResponseRecorder) EndResponse

func (w *ResponseRecorder) EndResponse()

EndResponse is auto-called when the whole client's request is done, releases the response recorder and its underline ResponseWriter.

func (*ResponseRecorder) Flush

func (w *ResponseRecorder) Flush()

Flush sends any buffered data to the client.

func (*ResponseRecorder) FlushResponse

func (w *ResponseRecorder) FlushResponse()

FlushResponse the full body, headers and status code to the underline response writer called automatically at the end of each request.

func (*ResponseRecorder) Push

func (w *ResponseRecorder) Push(target string, opts *http.PushOptions) error

Push initiates an HTTP/2 server push. This constructs a synthetic request using the given target and options, serializes that request into a PUSH_PROMISE frame, then dispatches that request using the server's request handler. If opts is nil, default options are used.

The target must either be an absolute path (like "/path") or an absolute URL that contains a valid host and the same scheme as the parent request. If the target is a path, it will inherit the scheme and host of the parent request.

The HTTP/2 spec disallows recursive pushes and cross-authority pushes. Push may or may not detect these invalid pushes; however, invalid pushes will be detected and canceled by conforming clients.

Handlers that wish to push URL X should call Push before sending any data that may trigger a request for URL X. This avoids a race where the client issues requests for X before receiving the PUSH_PROMISE for X.

Push returns ErrPushNotSupported if the client has disabled push or if push is not supported on the underlying connection.

func (*ResponseRecorder) Reset

func (w *ResponseRecorder) Reset()

Reset resets the response body, headers and the status code header.

func (*ResponseRecorder) ResetBody

func (w *ResponseRecorder) ResetBody()

ResetBody resets the response body.

func (*ResponseRecorder) ResetHeaders

func (w *ResponseRecorder) ResetHeaders()

ResetHeaders sets the headers to the underline's response writer's headers, may empty.

func (*ResponseRecorder) SetBody

func (w *ResponseRecorder) SetBody(b []byte)

SetBody overrides the body and sets it to a slice of bytes value.

func (*ResponseRecorder) SetBodyString

func (w *ResponseRecorder) SetBodyString(s string)

SetBodyString overrides the body and sets it to a string value.

func (*ResponseRecorder) Write

func (w *ResponseRecorder) Write(contents []byte) (int, error)

Write Adds the contents to the body reply, it writes the contents temporarily to a value in order to be flushed at the end of the request, this method give us the opportunity to reset the body if needed.

If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) before writing the data. If the Header does not contain a Content-Type line, Write adds a Content-Type set to the result of passing the initial 512 bytes of written data to DetectContentType.

Depending on the HTTP protocol version and the client, calling Write or WriteHeader may prevent future reads on the Request.Body. For HTTP/1.x requests, handlers should read any needed request body data before writing the response. Once the headers have been flushed (due to either an explicit Flusher.Flush call or writing enough data to trigger a flush), the request body may be unavailable. For HTTP/2 requests, the Go HTTP server permits handlers to continue to read the request body while concurrently writing the response. However, such behavior may not be supported by all HTTP/2 clients. Handlers should read before writing if possible to maximize compatibility.

func (*ResponseRecorder) WriteString

func (w *ResponseRecorder) WriteString(s string) (n int, err error)

WriteString writes a simple string to the response.

Returns the number of bytes written and any write error encountered

func (*ResponseRecorder) WriteTo

func (w *ResponseRecorder) WriteTo(res ResponseWriter)

WriteTo writes a response writer (temp: status code, headers and body) to another response writer

func (*ResponseRecorder) Writef

func (w *ResponseRecorder) Writef(format string, a ...interface{}) (n int, err error)

Writef formats according to a format specifier and writes to the response.

Returns the number of bytes written and any write error encountered.

type ResponseWriter

type ResponseWriter interface {
	http.ResponseWriter
	http.Flusher
	http.Hijacker
	http.CloseNotifier
	http.Pusher

	// BeginResponse receives an http.ResponseWriter
	// and initialize or reset the response writer's field's values.
	BeginResponse(http.ResponseWriter)

	// EndResponse is the last function which is called right before the server sent the final response.
	//
	// Here is the place which we can make the last checks or do a cleanup.
	EndResponse()

	// Writef formats according to a format specifier and writes to the response.
	//
	// Returns the number of bytes written and any write error encountered.
	Writef(format string, a ...interface{}) (n int, err error)

	// WriteString writes a simple string to the response.
	//
	// Returns the number of bytes written and any write error encountered.
	WriteString(s string) (n int, err error)

	// StatusCode returns the status code header value.
	StatusCode() int

	// Written should returns the total length of bytes that were being written to the client.
	// In addition ion provides some variables to help low-level actions:
	// NoWritten, means that nothing were written yet and the response writer is still live.
	// StatusCodeWritten, means that status code were written but no other bytes are written to the client, response writer may closed.
	// > 0 means that the reply was written and it's the total number of bytes were written.
	Written() int

	// SetBeforeFlush registers the unique callback which called exactly before the response is flushed to the client.
	SetBeforeFlush(cb func())
	// GetBeforeFlush returns (not execute) the before flush callback, or nil if not setted by SetBeforeFlush.
	GetBeforeFlush() func()
	// FlushResponse should be called only once before EndResponse.
	// it tries to send the status code if not sent already
	// and calls the  before flush callback, if any.
	//
	// FlushResponse can be called before EndResponse, but it should
	// be the last call of this response writer.
	FlushResponse()

	// clone returns a clone of this response writer
	// it copies the header, status code, headers and the beforeFlush finally  returns a new ResponseRecorder.
	Clone() ResponseWriter

	// WiteTo writes a response writer (temp: status code, headers and body) to another response writer
	WriteTo(ResponseWriter)
}

ResponseWriter interface is used by the context to serve an HTTP handler to construct an HTTP response.

Note: Only this ResponseWriter is an interface in order to be able for developers to change the response writer of the Context via `context.ResetResponseWriter`. The rest of the response writers implementations (ResponseRecorder & GzipResponseWriter) are coupled to the internal ResponseWriter implementation(*responseWriter).

A ResponseWriter may not be used after the Handler has returned.

func AcquireResponseWriter

func AcquireResponseWriter() ResponseWriter

AcquireResponseWriter returns a new *ResponseWriter from the pool. Releasing is done automatically when request and response is done.

type Transaction

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

Transaction gives the users the opportunity to code their route handlers cleaner and safier it receives a scope which is decided when to send an error to the user, recover from panics stop the execution of the next transactions and so on...

it's default scope is the TransientTransactionScope which is silently skips the current transaction's response if transaction.Complete accepts a non-empty error.

Create and set custom transactions scopes with transaction.SetScope.

For more information please visit the tests.

func (*Transaction) Complete

func (t *Transaction) Complete(err error)

Complete completes the transaction rollback and send an error when the error is not empty. The next steps depends on its Scope.

The error can be a type of context.NewTransactionErrResult().

func (*Transaction) Context

func (t *Transaction) Context() Context

Context returns the current context of the transaction.

func (*Transaction) SetScope

func (t *Transaction) SetScope(scope TransactionScope)

SetScope sets the current transaction's scope ion.RequestTransactionScope || ion.TransientTransactionScope (default).

type TransactionErrResult

type TransactionErrResult struct {
	StatusCode int
	// if reason is empty then the already relative registered (custom or not)
	// error will be executed if the scope allows that.
	Reason      string
	ContentType string
}

TransactionErrResult could be named also something like 'MaybeError', it is useful to send it on transaction.Complete in order to execute a custom error mesasge to the user.

in simple words it's just a 'traveler message' between the transaction and its scope. it is totally optional

func NewTransactionErrResult

func NewTransactionErrResult() TransactionErrResult

NewTransactionErrResult returns a new transaction result with the given error message, it can be empty too, but if not then the transaction's scope is decided what to do with that

func (TransactionErrResult) Error

func (err TransactionErrResult) Error() string

Error returns the reason given by the user or an empty string

func (TransactionErrResult) IsFailure

func (err TransactionErrResult) IsFailure() bool

IsFailure returns true if this is an actual error

type TransactionScope

type TransactionScope interface {
	// EndTransaction returns if can continue to the next transactions or not (false)
	// called after Complete, empty or not empty error
	EndTransaction(maybeErr TransactionErrResult, ctx Context) bool
}

TransactionScope is the manager of the transaction's response, can be resseted and skipped from its parent context or execute an error or skip other transactions

type TransactionScopeFunc

type TransactionScopeFunc func(maybeErr TransactionErrResult, ctx Context) bool

TransactionScopeFunc the transaction's scope signature

func (TransactionScopeFunc) EndTransaction

func (tsf TransactionScopeFunc) EndTransaction(maybeErr TransactionErrResult, ctx Context) bool

EndTransaction ends the transaction with a callback to itself, implements the TransactionScope interface

type Unmarshaler

type Unmarshaler interface {
	Unmarshal(data []byte, v interface{}) error
}

Unmarshaler is the interface implemented by types that can unmarshal any raw data TIP INFO: Any v object which implements the BodyDecoder can be override the unmarshaler.

type UnmarshalerFunc

type UnmarshalerFunc func(data []byte, v interface{}) error

UnmarshalerFunc a shortcut for the Unmarshaler interface

See 'Unmarshaler' and 'BodyDecoder' for more.

func (UnmarshalerFunc) Unmarshal

func (u UnmarshalerFunc) Unmarshal(data []byte, v interface{}) error

Unmarshal parses the X-encoded data and stores the result in the value pointed to by v. Unmarshal uses the inverse of the encodings that Marshal uses, allocating maps, slices, and pointers as necessary.

type XML

type XML struct {
	// content-specific
	Indent string
	Prefix string
}

XML contains the options for the XML (Context's) Renderer.

Jump to

Keyboard shortcuts

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