Documentation ¶
Overview ¶
Package lars - Library Access/Retrieval System, is a fast radix-tree based, zero allocation, HTTP router for Go.
Usage ¶
Below is a simple example, for a full example see here https://github.com/go-playground/lars/blob/master/_examples/all-in-one/main.go
package main import ( "net/http" "github.com/go-playground/lars" mw "github.com/go-playground/lars/_examples/middleware/logging-recovery" ) func main() { l := lars.New() l.Use(mw.LoggingAndRecovery) // LoggingAndRecovery is just an example copy // paste and modify to your needs l.Get("/", HelloWorld) http.ListenAndServe(":3007", l.Serve()) } // HelloWorld ... func HelloWorld(c lars.Context) { c.Response().Write([]byte("Hello World")) // this will also work, Response() complies with http.ResponseWriter interface fmt.Fprint(c.Response(), "Hello World") }
URL Params ¶
example param usage
l := l.New() l.Get("/user/:id", UserHandler) // serve css, js etc.. c.Param(lars.WildcardParam) will return the // remaining path if you need to use it in a custom handler... l.Get("/static/*", http.FileServer(http.Dir("static/"))) NOTE: Since this router has only explicit matches, you can not register static routes and parameters for the same path segment. For example you can not register the patterns /user/new and /user/:user for the same request method at the same time. The routing of different request methods is independent from each other. I was initially against this, and this router allowed it in a previous version, however it nearly cost me in a big app where the dynamic param value say :type actually could have matched another static route and that's just too dangerous, so it is no longer allowed.
Groups ¶
example group definitions
... l.Use(LoggingAndRecovery) ... l.Post("/users/add", ...) // creates a group for user + inherits all middleware registered using l.Use() user := l.Group("/user/:userid") user.Get("", ...) user.Post("", ...) user.Delete("/delete", ...) contactInfo := user.Group("/contact-info/:ciid") contactinfo.Delete("/delete", ...) // creates a group for others + inherits all middleware registered using l.Use() + // adds OtherHandler to middleware others := l.GroupWithMore("/others", OtherHandler) // creates a group for admin WITH NO MIDDLEWARE... more can be added using admin.Use() admin := l.GroupWithNone("/admin") admin.Use(SomeAdminSecurityMiddleware) ...
Custom Context - Avoid Type Casting - Custom Handlers ¶
example context + custom handlers
... // MyContext is a custom context type MyContext struct { *lars.Ctx // a little dash of Duck Typing.... } // CustomContextFunction is a function that is specific to your applications // needs that you added func (mc *MyContext) CustomContextFunction() { // do something } // newContext is the function that creates your custom context + // contains lars's default context func newContext(l *lars.LARS) lars.Context { return &MyContext{ Ctx: lars.NewContext(l), } } // casts custom context and calls you custom handler so you don't have to // type cast lars.Context everywhere func castCustomContext(c lars.Context, handler lars.Handler) { // could do it in all one statement, but in long form for readability h := handler.(func(*MyContext)) ctx := c.(*MyContext) h(ctx) } func main() { l := lars.New() l.RegisterContext(newContext) // all gets cached in pools for you l.RegisterCustomHandler(func(*MyContext) {}, castCustomContext) l.Use(Logger) l.Get("/", Home) http.ListenAndServe(":3007", l.Serve()) } // Home ...notice the receiver is *MyContext, castCustomContext handled the // type casting for us; quite the time saver if you ask me. func Home(c *MyContext) { c.CustomContextFunction() ... }
Decoding Body ¶
For full example see https://github.com/go-playground/lars/blob/master/_examples/decode/main.go currently JSON, XML, FORM + Multipart Form's are support out of the box.
// first argument denotes yes or no I would like URL query parameter fields // to be included. i.e. 'id' in route '/user/:id' should it be included. // run, then change to false and you'll see user.ID is not populated. if err := c.Decode(true, maxBytes, &user); err != nil { log.Println(err) }
Misc ¶
misc examples and noteworthy features
... // can register multiple handlers, the last is considered the last in the chain and // others considered middleware, but just for this route and not added to middleware // like l.Use() does. l.Get(/"home", AdditionalHandler, HomeHandler) // set custom 404 ( not Found ) handler l.Register404(404Handler) // Redirect to or from ending slash if route not found, default is true l.SetRedirectTrailingSlash(true) // Handle 405 ( Method Not allowed ), default is false l.SetHandle405MethodNotAllowed(false) // automatically handle OPTION requests; manually configured // OPTION handlers take precedence. default true l.SetAutomaticallyHandleOPTIONS(set bool) // register custom context l.RegisterContext(ContextFunc) // Register custom handler type, see util.go // https://github.com/go-playground/lars/blob/master/util.go#L62 for example handler // creation l.RegisterCustomHandler(interface{}, CustomHandlerFunc) // NativeChainHandler is used as a helper to create your own custom handlers, or use // custom handlers that already exist an example usage can be found here // https://github.com/go-playground/lars/blob/master/util.go#L86, below is an example // using nosurf CSRF middleware l.Use(nosurf.NewPure(lars.NativeChainHandler)) // Context has 2 methods of which you should be aware of ParseForm and // ParseMulipartForm, they just call the default http functions but provide one more // additional feature, they copy the URL params to the request Forms variables, just // like Query parameters would have been. The functions are for convenience and are // totally optional.
Index ¶
- Constants
- Variables
- type Context
- type ContextFunc
- type Ctx
- func (c *Ctx) AcceptedLanguages(lowercase bool) []string
- func (c *Ctx) Attachment(r io.Reader, filename string) (err error)
- func (c *Ctx) BaseContext() *Ctx
- func (c *Ctx) ClientIP() (clientIP string)
- func (c *Ctx) Context() context.Context
- func (c *Ctx) Deadline() (deadline time.Time, ok bool)
- func (c *Ctx) Decode(includeFormQueryParams bool, maxMemory int64, v interface{}) (err error)
- func (c *Ctx) Done() <-chan struct{}
- func (c *Ctx) Err() error
- func (c *Ctx) Get(key interface{}) (value interface{}, exists bool)
- func (c *Ctx) HandlerName() string
- func (c *Ctx) Inline(r io.Reader, filename string) (err error)
- func (c *Ctx) JSON(code int, i interface{}) (err error)
- func (c *Ctx) JSONBytes(code int, b []byte) (err error)
- func (c *Ctx) JSONP(code int, i interface{}, callback string) (err error)
- func (c *Ctx) Next()
- func (c *Ctx) Param(name string) string
- func (c *Ctx) ParseForm() error
- func (c *Ctx) ParseMultipartForm(maxMemory int64) error
- func (c *Ctx) QueryParams() url.Values
- func (c *Ctx) Request() *http.Request
- func (c *Ctx) RequestEnd()
- func (c *Ctx) RequestStart(w http.ResponseWriter, r *http.Request)
- func (c *Ctx) Response() *Response
- func (c *Ctx) Set(key interface{}, value interface{})
- func (c *Ctx) Stream(step func(w io.Writer) bool)
- func (c *Ctx) Text(code int, s string) error
- func (c *Ctx) TextBytes(code int, b []byte) (err error)
- func (c *Ctx) Value(key interface{}) interface{}
- func (c *Ctx) WebSocket() *websocket.Conn
- func (c *Ctx) WithCancel() context.CancelFunc
- func (c *Ctx) WithContext(ctx context.Context)
- func (c *Ctx) WithDeadline(deadline time.Time) context.CancelFunc
- func (c *Ctx) WithTimeout(timeout time.Duration) context.CancelFunc
- func (c *Ctx) WithValue(key interface{}, val interface{})
- func (c *Ctx) XML(code int, i interface{}) error
- func (c *Ctx) XMLBytes(code int, b []byte) (err error)
- type CustomHandlerFunc
- type Handler
- type HandlerFunc
- type HandlersChain
- type IRouteGroup
- type IRoutes
- type LARS
- func (g *LARS) Any(path string, h ...Handler)
- func (l *LARS) BuiltInFormDecoder() *form.Decoder
- func (g *LARS) Connect(path string, h ...Handler)
- func (g *LARS) Delete(path string, h ...Handler)
- func (g *LARS) Get(path string, h ...Handler)
- func (g *LARS) Group(prefix string) IRouteGroup
- func (g *LARS) GroupWithMore(prefix string, middleware ...Handler) IRouteGroup
- func (g *LARS) GroupWithNone(prefix string) IRouteGroup
- func (g *LARS) Handle(method string, path string, h ...Handler)
- func (g *LARS) Head(path string, h ...Handler)
- func (g *LARS) Match(methods []string, path string, h ...Handler)
- func (g *LARS) Options(path string, h ...Handler)
- func (g *LARS) Patch(path string, h ...Handler)
- func (g *LARS) Post(path string, h ...Handler)
- func (g *LARS) Put(path string, h ...Handler)
- func (l *LARS) Register404(notFound ...Handler)
- func (l *LARS) RegisterContext(fn ContextFunc)
- func (l *LARS) RegisterCustomHandler(customType interface{}, fn CustomHandlerFunc)
- func (l *LARS) Serve() http.Handler
- func (l *LARS) SetAutomaticallyHandleOPTIONS(set bool)
- func (l *LARS) SetHandle405MethodNotAllowed(set bool)
- func (l *LARS) SetRedirectTrailingSlash(set bool)
- func (g *LARS) Trace(path string, h ...Handler)
- func (g *LARS) Use(m ...Handler)
- func (g *LARS) WebSocket(upgrader websocket.Upgrader, path string, h Handler)
- type Param
- type Params
- type Response
- func (r *Response) CloseNotify() <-chan bool
- func (r *Response) Committed() bool
- func (r *Response) Flush()
- func (r *Response) Header() http.Header
- func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error)
- func (r *Response) SetWriter(w http.ResponseWriter)
- func (r *Response) Size() int64
- func (r *Response) Status() int
- func (r *Response) Write(b []byte) (n int, err error)
- func (r *Response) WriteHeader(code int)
- func (r *Response) WriteString(s string) (n int, err error)
- func (r *Response) Writer() http.ResponseWriter
- type RouteMap
Constants ¶
const ( // CONNECT HTTP method CONNECT = http.MethodConnect // DELETE HTTP method DELETE = http.MethodDelete // GET HTTP method GET = http.MethodGet // HEAD HTTP method HEAD = http.MethodHead // OPTIONS HTTP method OPTIONS = http.MethodOptions // PATCH HTTP method PATCH = http.MethodPatch // POST HTTP method POST = http.MethodPost // PUT HTTP method PUT = http.MethodPut // TRACE HTTP method TRACE = http.MethodTrace ApplicationJSON = "application/json" ApplicationJSONCharsetUTF8 = ApplicationJSON + "; " + CharsetUTF8 ApplicationJavaScript = "application/javascript" ApplicationJavaScriptCharsetUTF8 = ApplicationJavaScript + "; " + CharsetUTF8 ApplicationXML = "application/xml" ApplicationXMLCharsetUTF8 = ApplicationXML + "; " + CharsetUTF8 ApplicationForm = "application/x-www-form-urlencoded" ApplicationProtobuf = "application/protobuf" ApplicationMsgpack = "application/msgpack" TextHTML = "text/html" TextHTMLCharsetUTF8 = TextHTML + "; " + CharsetUTF8 TextPlain = "text/plain" TextPlainCharsetUTF8 = TextPlain + "; " + CharsetUTF8 MultipartForm = "multipart/form-data" OctetStream = "application/octet-stream" CharsetUTF8 = "charset=utf-8" AcceptedLanguage = "Accept-Language" AcceptEncoding = "Accept-Encoding" Authorization = "Authorization" ContentDisposition = "Content-Disposition" ContentEncoding = "Content-Encoding" ContentLength = "Content-Length" ContentType = "Content-Type" Location = "Location" Upgrade = "Upgrade" Vary = "Vary" WWWAuthenticate = "WWW-Authenticate" XForwardedFor = "X-Forwarded-For" XRealIP = "X-Real-Ip" Allow = "Allow" Origin = "Origin" Gzip = "gzip" WildcardParam = "*wildcard" )
HTTP Constant Terms and Variables
Variables ¶
var NativeChainHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { c := GetContext(w) b := c.BaseContext() b.request = r if b.index+1 < len(b.handlers) { c.Next() } })
NativeChainHandler is used in native handler chain middleware example using nosurf crsf middleware nosurf.NewPure(lars.NativeChainHandler)
Functions ¶
This section is empty.
Types ¶
type Context ¶
type Context interface { context.Context Request() *http.Request Response() *Response WebSocket() *websocket.Conn Param(name string) string QueryParams() url.Values ParseForm() error ParseMultipartForm(maxMemory int64) error Set(key interface{}, value interface{}) Get(key interface{}) (value interface{}, exists bool) Context() context.Context WithContext(context.Context) WithCancel() context.CancelFunc WithDeadline(time.Time) context.CancelFunc WithTimeout(time.Duration) context.CancelFunc WithValue(key interface{}, val interface{}) Next() RequestStart(w http.ResponseWriter, r *http.Request) RequestEnd() ClientIP() (clientIP string) AcceptedLanguages(lowercase bool) []string HandlerName() string Stream(step func(w io.Writer) bool) JSON(int, interface{}) error JSONBytes(int, []byte) error JSONP(int, interface{}, string) error XML(int, interface{}) error XMLBytes(int, []byte) error Text(int, string) error TextBytes(int, []byte) error Attachment(r io.Reader, filename string) (err error) Inline(r io.Reader, filename string) (err error) Decode(includeFormQueryParams bool, maxMemory int64, v interface{}) (err error) BaseContext() *Ctx }
Context is the context interface type
func GetContext ¶
func GetContext(w http.ResponseWriter) Context
GetContext is a helper method for retrieving the Context object from the ResponseWriter when using native go hanlders. NOTE: this will panic if fed an http.ResponseWriter not provided by lars's chaining.
type ContextFunc ¶
ContextFunc is the function to run when creating a new context
type Ctx ¶
type Ctx struct {
// contains filtered or unexported fields
}
Ctx encapsulates the http request, response context
func NewContext ¶
NewContext returns a new default lars Context object.
func (*Ctx) AcceptedLanguages ¶
AcceptedLanguages returns an array of accepted languages denoted by the Accept-Language header sent by the browser NOTE: some stupid browsers send in locales lowercase when all the rest send it properly
func (*Ctx) Attachment ¶
Attachment is a helper method for returning an attachement file to be downloaded, if you with to open inline see function
func (*Ctx) BaseContext ¶
BaseContext returns the underlying context object LARS uses internally. used when overriding the context object
func (*Ctx) ClientIP ¶
ClientIP implements a best effort algorithm to return the real client IP, it parses X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy.
func (*Ctx) Context ¶
Context returns the request's context. To change the context, use WithContext.
The returned context is always non-nil.
func (*Ctx) Decode ¶
Decode takes the request and attempts to discover it's content type via the http headers and then decode the request body into the provided struct. Example if header was "application/json" would decode using json.NewDecoder(io.LimitReader(c.request.Body, maxMemory)).Decode(v).
func (*Ctx) Get ¶
Get returns the value for the given key and is a shortcut for context.Value(...) ... but it also returns if the value was found or not.
func (*Ctx) HandlerName ¶
HandlerName returns the current Contexts final handler's name
func (*Ctx) Inline ¶
Inline is a helper method for returning a file inline to be rendered/opened by the browser
func (*Ctx) JSONP ¶
JSONP sends a JSONP response with status code and uses `callback` to construct the JSONP payload.
func (*Ctx) Next ¶
func (c *Ctx) Next()
Next should be used only inside middleware. It executes the pending handlers in the chain inside the calling handler. See example in github.
func (*Ctx) Param ¶
Param returns the value of the first Param which key matches the given name. If no matching Param is found, an empty string is returned.
func (*Ctx) ParseForm ¶
ParseForm calls the underlying http.Request ParseForm but also adds the URL params to the request Form as if they were defined as query params i.e. ?id=13&ok=true but does not add the params to the http.Request.URL.RawQuery for SEO purposes
func (*Ctx) ParseMultipartForm ¶
ParseMultipartForm calls the underlying http.Request ParseMultipartForm but also adds the URL params to the request Form as if they were defined as query params i.e. ?id=13&ok=true but does not add the params to the http.Request.URL.RawQuery for SEO purposes
func (*Ctx) QueryParams ¶
QueryParams returns the http.Request.URL.Query() values this function is not for convenience, but rather performance URL.Query() reparses the RawQuery every time it's called, but this function will cache the initial parsing so it doesn't have to reparse; which is useful if when accessing these Params from multiple middleware.
func (*Ctx) RequestEnd ¶
func (c *Ctx) RequestEnd()
RequestEnd fires after request completes and just before the *Ctx object gets put back into the pool. Used to close DB connections and such on a custom context
func (*Ctx) RequestStart ¶
func (c *Ctx) RequestStart(w http.ResponseWriter, r *http.Request)
RequestStart resets the Context to it's default request state
func (*Ctx) Set ¶
func (c *Ctx) Set(key interface{}, value interface{})
Set is used to store a new key/value pair using the context contained on this Ctx. It is a shortcut for context.WithValue(..., ...)
func (*Ctx) Value ¶
func (c *Ctx) Value(key interface{}) interface{}
Value calls the underlying context.Value()
func (*Ctx) WithCancel ¶
func (c *Ctx) WithCancel() context.CancelFunc
WithCancel calls context.WithCancel and automatically updates context on the containing lars.Ctx object.
func (*Ctx) WithContext ¶
WithContext updates the underlying request's context with to ctx The provided ctx must be non-nil.
func (*Ctx) WithDeadline ¶
func (c *Ctx) WithDeadline(deadline time.Time) context.CancelFunc
WithDeadline calls context.WithDeadline and automatically updates context on the containing lars.Ctx object.
func (*Ctx) WithTimeout ¶
func (c *Ctx) WithTimeout(timeout time.Duration) context.CancelFunc
WithTimeout calls context.WithTimeout and automatically updates context on the containing lars.Ctx object.
func (*Ctx) WithValue ¶
func (c *Ctx) WithValue(key interface{}, val interface{})
WithValue calls golang.org/x/net/context WithValue and automatically updates context on the containing lars.Ctx object. Can also use Set() function on Ctx object (Recommended)
type CustomHandlerFunc ¶
CustomHandlerFunc wraped by HandlerFunc and called where you can type cast both Context and Handler and call Handler
type Handler ¶
type Handler interface{}
Handler is the type used in registering handlers. NOTE: these handlers may get wrapped by the HandlerFunc type internally.
type HandlerFunc ¶
type HandlerFunc func(Context)
HandlerFunc is the internal handler type used for middleware and handlers
type HandlersChain ¶
type HandlersChain []HandlerFunc
HandlersChain is an array of HanderFunc handlers to run
type IRouteGroup ¶
type IRouteGroup interface { IRoutes GroupWithNone(prefix string) IRouteGroup GroupWithMore(prefix string, middleware ...Handler) IRouteGroup Group(prefix string) IRouteGroup }
IRouteGroup interface for router group
type IRoutes ¶
type IRoutes interface { Use(...Handler) Any(string, ...Handler) Get(string, ...Handler) Post(string, ...Handler) Delete(string, ...Handler) Patch(string, ...Handler) Put(string, ...Handler) Options(string, ...Handler) Head(string, ...Handler) Connect(string, ...Handler) Trace(string, ...Handler) WebSocket(websocket.Upgrader, string, Handler) }
IRoutes interface for routes
type LARS ¶
type LARS struct {
// contains filtered or unexported fields
}
LARS is the main routing instance
func (*LARS) BuiltInFormDecoder ¶
BuiltInFormDecoder returns the built in form decoder github.com/go-playground/form in order for custom type to be registered.
func (*LARS) Group ¶
func (g *LARS) Group(prefix string) IRouteGroup
Group creates a new sub router with specified prefix and retains existing middleware.
func (*LARS) GroupWithMore ¶
func (g *LARS) GroupWithMore(prefix string, middleware ...Handler) IRouteGroup
GroupWithMore creates a new sub router with specified prefix, retains existing middleware and adds new middleware.
func (*LARS) GroupWithNone ¶
func (g *LARS) GroupWithNone(prefix string) IRouteGroup
GroupWithNone creates a new sub router with specified prefix and no middleware attached.
func (*LARS) Handle ¶
Handle allows for any method to be registered with the given route & handler. Allows for non standard methods to be used like CalDavs PROPFIND and so forth.
func (*LARS) Register404 ¶
Register404 alows for overriding of the not found handler function. NOTE: this is run after not finding a route even after redirecting with the trailing slash
func (*LARS) RegisterContext ¶
func (l *LARS) RegisterContext(fn ContextFunc)
RegisterContext registers a custom Context function for creation and resetting of a global object passed per http request
func (*LARS) RegisterCustomHandler ¶
func (l *LARS) RegisterCustomHandler(customType interface{}, fn CustomHandlerFunc)
RegisterCustomHandler registers a custom handler that gets wrapped by HandlerFunc
func (*LARS) SetAutomaticallyHandleOPTIONS ¶
SetAutomaticallyHandleOPTIONS tells lars whether to automatically handle OPTION requests; manually configured OPTION handlers take precedence. default true
func (*LARS) SetHandle405MethodNotAllowed ¶
SetHandle405MethodNotAllowed tells lars whether to handle the http 405 Method Not Allowed status code
func (*LARS) SetRedirectTrailingSlash ¶
SetRedirectTrailingSlash tells lars whether to try and fix a URL by trying to find it lowercase -> with or without slash -> 404
type Params ¶
type Params []Param
Params is a Param-slice, as returned by the router. The slice is ordered, the first URL parameter is also the first slice value. It is therefore safe to read values by the index.
type Response ¶
type Response struct { http.ResponseWriter // contains filtered or unexported fields }
Response struct contains methods and to capture extra data about the http request and more efficiently reset underlying writer object... it does comply with the http.ResponseWriter interface
func (*Response) CloseNotify ¶
CloseNotify wraps response writer's CloseNotify function.
func (*Response) Committed ¶
Committed returns whether the *Response header has already been written to and if has been committed to this return.
func (*Response) Header ¶
Header returns the header map that will be sent by WriteHeader. Changing the header after a call to WriteHeader (or Write) has no effect unless the modified headers were declared as trailers by setting the "Trailer" header before the call to WriteHeader (see example). To suppress implicit *Response headers, set their value to nil.
func (*Response) SetWriter ¶
func (r *Response) SetWriter(w http.ResponseWriter)
SetWriter sets the provided writer as the new *Response http.ResponseWriter
func (*Response) Write ¶
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.
func (*Response) WriteHeader ¶
WriteHeader sends an HTTP *Response header with status code. If WriteHeader is not called explicitly, the first call to Write will trigger an implicit WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly used to send error codes.
func (*Response) WriteString ¶
WriteString write string to ResponseWriter
func (*Response) Writer ¶
func (r *Response) Writer() http.ResponseWriter
Writer return the *Response's http.ResponseWriter object. Usually only used when creating middleware.