goro

package module
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Feb 1, 2020 License: BSD-3-Clause Imports: 14 Imported by: 0

README

Goro is a mighty fine routing toolkit for Go web applications. It is designed to be fast, yet flexible.

CircleCI Go Version codecov

Features

Goro is LOADED with features, but no bloat.

  • Straightforward context handling / management
  • Flexible routing options with wildcards and variables
  • Prioritized route definitions with caching
  • Pre and Post execution Filters to modify Request or HandlerContext objects or to perform post-execution logic if embedding.
  • Static asset mapping
  • Support for subdomains
  • Handler chaining built-in

Installing

To install, run:

go get -u github.com/theyakka/goro

You can then import goro using:

import github.com/theyakka/goro

Getting started

Setting up a basic router would look something like the following.

In your main/server.go file you would create a Router instance, configure a basic route, and then pass the router to http.ListenAndServe as a handler.

package main

func startServer() {
	router := goro.NewRouter()
	router.GET("/").Handle(handlers.RootHandler)
	log.Fatal(http.ListenAndServe(":8080", router))
}

Then in your handlers package (or where you define your routes) you would set up your RootHandler function.

package handlers

func RootHandler(ctx *goro.HandlerContext) {
	// do something here
}

That's just a quick intro. However, Goro has so much more packed in. Rather than try to describe it all here, you should check out The Goro Guide.

We recommend using the latest version of Go.

FAQ

Why should I use this and not ____?

I'm not going to make any claims that Goro is the fastest router on the market or that it'll make you a million bucks. The likelihood is that even if those were true for you, they might not be for others.

What we will say is that we have tried A LOT of web frameworks over many languages and that we invested in making Goro out of unhappiness with what we saw generally. If you're here, then maybe you have also.

Goro was designed from the ground up as a Router that we wanted to use and not to copy anyone else. It has the features we think are important, and is architected in a way that we think makes managing all this stuff super simple.

Give it a try and if you like it, let us know! Either way, we love feedback.

Has it been tested in production? Can I use it in production?

The code here has been written based on experiences with clients of all sizes. It has been production tested. That said, code is always evolving. We plan to keep on using it in production but we also plan to keep on improving it. If you find a bug, let us know!

Who the f*ck is Yakka?

Yakka is the premier Flutter agency and a kick-ass product company. We focus on the work. Our stuff is at http://theyakka.com. Go check it out.

Outro

Credits

Goro is sponsored, owned and maintained by Yakka LLC. Feel free to reach out with suggestions, ideas or to say hey.

Security

If you believe you have identified a serious security vulnerability or issue with Goro, please report it as soon as possible to apps@theyakka.com. Please refrain from posting it to the public issue tracker so that we have a chance to address it and notify everyone accordingly.

License

Goro is released under a modified MIT license. See LICENSE for details.

Documentation

Index

Constants

View Source
const (
	StateKeyHasExecutedPreFilters  = "_goro.skey.hasExecutedPreFilters"
	StateKeyHasExecutedPostFilters = "_goro.skey.hasExecutedPostFilters"
)
View Source
const (
	// RouteInfoKeyIsRoot - does the route have wildcard parts
	RouteInfoKeyIsRoot string = "is_root"

	// RouteInfoKeyDescription - does the route have a catch all part
	RouteInfoKeyDescription string = "description"
)
View Source
const DomainMapNakedSubdomainKey = ":naked"
View Source
const DomainMapWildcardSubdomainKey = ":wildcard"
View Source
const RootPath = "/"

RootPath - string representation of the root path

Variables

This section is empty.

Functions

func CleanPath added in v0.2.0

func CleanPath(path string) string

CleanPath - returns a path value with the following modifications:

  1. replaces any '\' with '/'
  2. replaces any '//' with '/'
  3. adds a leading '/' (if missing)

func IsEmptyRoutingError added in v0.2.0

func IsEmptyRoutingError(re RoutingError) bool

func Log

func Log(v ...interface{})

Log - logging wrapper for standard output to log

func ServeFile added in v0.2.0

func ServeFile(ctx *HandlerContext, filename string, statusCode int)

ServeFile replies to the request with the contents of the named file.

This implementation is different to the standard library implementation in that it doesn't concern itself with directories, and does not account for redirecting paths ending in /index.html. If you wish to retain that functionality, you should set up your routes accordingly.

ServeFile will only catch common errors, for example 404s or access related errors and wont catch lower-level errors. Due to the implementation details in the Go standard library (which we still rely on) some of those errors will fall through to the standard error reporting mechanisms.

Types

type Bundle added in v0.2.0

type Bundle interface {
	PreFilters() []*Filter
	PostFilters() []*Filter
	Routes() []*Route
}

type CacheEntry

type CacheEntry struct {
	Params map[string]interface{}
	Route  *Route
	// contains filtered or unexported fields
}

CacheEntry - an entry in the route cache

func NotFoundCacheEntry

func NotFoundCacheEntry() CacheEntry

NotFoundCacheEntry - represents the inability to find an entry in the cache

type Chain

type Chain struct {

	// RouterCatchesErrors - if true and the chain is attached to a router then
	// errors will bubble up to the router error handler
	RouterCatchesErrors bool

	// EmitHTTPError - if true, the router will emit an http.Error when the chain
	// result is an error
	EmitHTTPError bool

	// ChainCompletedFunc - called when chain completes
	ChainCompletedFunc ChainCompletedFunc
	// contains filtered or unexported fields
}

Chain allows for chaining of Handlers

func HC added in v0.2.0

func HC(router *Router, handlers ...ChainHandler) Chain

func NewChain

func NewChain(router *Router, handlers ...ChainHandler) Chain

NewChain - creates a new Chain instance

func (*Chain) Append added in v0.2.0

func (ch *Chain) Append(handlers ...ChainHandler) Chain

Append - returns a new chain with the ChainHandler appended to the list of handlers

func (Chain) Call added in v0.2.0

func (ch Chain) Call() ContextHandlerFunc

Call - calls the chain

func (Chain) Copy added in v0.2.0

func (ch Chain) Copy() Chain

func (*Chain) Error added in v0.2.0

func (ch *Chain) Error(ctx *HandlerContext, chainError error, statusCode int)

Error - halt the chain and report an error

func (*Chain) Halt added in v0.2.0

func (ch *Chain) Halt(ctx *HandlerContext)

Halt - halt chain execution

func (*Chain) Next added in v0.2.0

func (ch *Chain) Next(ctx *HandlerContext)

Next - execute the next handler in the chain

func (Chain) Then

func (ch Chain) Then(handler ContextHandlerFunc) ContextHandlerFunc

Then - calls the chain and then the designated Handler

type ChainCompletedFunc added in v0.2.0

type ChainCompletedFunc func(result ChainResult)

ChainCompletedFunc - callback function executed when chain execution has completed

type ChainHandler added in v0.2.0

type ChainHandler func(*Chain, *HandlerContext)

type ChainResult added in v0.2.0

type ChainResult struct {
	Status     ChainStatus
	Error      error
	StatusCode int
}

ChainResult - the chain execution result

type ChainStatus added in v0.2.0

type ChainStatus int

ChainStatus - the status of the chain

const (
	// ChainCompleted - the chain completed normally
	ChainCompleted ChainStatus = 1 << iota
	// ChainError - the chain was stopped because of an error
	ChainError
	// ChainHalted - the chain was halted before it could finish executing
	ChainHalted
)

type CheckedResponseWriter added in v0.2.0

type CheckedResponseWriter struct {
	http.ResponseWriter
	// contains filtered or unexported fields
}

func NewCheckedResponseWriter added in v0.2.0

func NewCheckedResponseWriter(w http.ResponseWriter) *CheckedResponseWriter

func (*CheckedResponseWriter) Write added in v0.2.0

func (w *CheckedResponseWriter) Write(b []byte) (int, error)

func (*CheckedResponseWriter) WriteHeader added in v0.2.0

func (w *CheckedResponseWriter) WriteHeader(status int)

type ContextHandler added in v0.2.0

type ContextHandler interface {
	Serve(ctx *HandlerContext)
}

ContextHandler - the standard Goro handler

type ContextHandlerFunc added in v0.3.0

type ContextHandlerFunc func(ctx *HandlerContext)

ContextHandlerFunc - the standard Goro handler

func (ContextHandlerFunc) Serve added in v0.3.0

func (chf ContextHandlerFunc) Serve(ctx *HandlerContext)

Serve - implement the ContextHandler interface

type DebugLevel

type DebugLevel int

DebugLevel - Debug information output level

const (
	// DebugLevelNone - debugging is off
	DebugLevelNone DebugLevel = 1 << iota
	// DebugLevelTimings - show timings only
	DebugLevelTimings
	// DebugLevelFull - show all debugging information
	DebugLevelFull
)

type DomainMap

type DomainMap struct {

	// NotFoundHandler - if the (sub)domain is not mapped, call this handler
	NotFoundHandler ContextHandlerFunc
	// contains filtered or unexported fields
}

DomainMap - maps (sub)domains to routers

func NewDomainMap

func NewDomainMap(domains ...string) *DomainMap

NewDomainMap - creates a new domain map for the provided domains

func (*DomainMap) AddRouter

func (dm *DomainMap) AddRouter(subdomain string, router *Router)

AddRouter - Register a router for a domain pattern (regex)

func (*DomainMap) NewRouter

func (dm *DomainMap) NewRouter(subdomainPattern string) *Router

NewRouter - Creates a new Router, registers it in the domain map and returns it for use

func (*DomainMap) NewRouters added in v0.2.0

func (dm *DomainMap) NewRouters(subdomains ...string) []*Router

NewRouters - Creates a new Router for each of the defined subdomains and registers it with the DomainMap

func (*DomainMap) ServeHTTP

func (dm *DomainMap) ServeHTTP(w http.ResponseWriter, req *http.Request)

type ErrorInfoMap added in v0.2.0

type ErrorInfoMap map[string]interface{}

type Filter

type Filter interface {
	ExecuteBefore(ctx *HandlerContext)
	ExecuteAfter(ctx *HandlerContext)
}

Filter is an interface that can be registered on the Router to apply custom logic to modify the Request or calling Context

type Group added in v0.2.0

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

func NewGroup added in v0.2.0

func NewGroup(prefix string, router *Router) *Group

func (*Group) Add added in v0.2.0

func (g *Group) Add(method string, routePath string) *Route

Add creates a new Route and registers the instance within the Router

func (*Group) DELETE added in v0.2.0

func (g *Group) DELETE(routePath string) *Route

Add creates a new Route using the DELETE method and registers the instance within the Router

func (*Group) GET added in v0.2.0

func (g *Group) GET(routePath string) *Route

Add creates a new Route using the GET method and registers the instance within the Router

func (*Group) Group added in v0.2.0

func (g *Group) Group(prefix string) *Group

func (*Group) HEAD added in v0.2.0

func (g *Group) HEAD(routePath string) *Route

Add creates a new Route using the HEAD method and registers the instance within the Router

func (*Group) OPTIONS added in v0.2.0

func (g *Group) OPTIONS(routePath string) *Route

Add creates a new Route using the OPTIONS method and registers the instance within the Router

func (*Group) PATCH added in v0.2.0

func (g *Group) PATCH(routePath string) *Route

Add creates a new Route using the PATCH method and registers the instance within the Router

func (*Group) POST added in v0.2.0

func (g *Group) POST(routePath string) *Route

Add creates a new Route using the POST method and registers the instance within the Router

func (*Group) PUT added in v0.2.0

func (g *Group) PUT(routePath string) *Route

Add creates a new Route using the PUT method and registers the instance within the Router

type HandlerContext added in v0.2.0

type HandlerContext struct {
	sync.RWMutex
	Request        *http.Request
	ResponseWriter http.ResponseWriter
	Parameters     *Parameters
	Meta           map[string]interface{}
	Path           string
	CatchAllValue  string
	Errors         []RoutingError
	// contains filtered or unexported fields
}

func NewHandlerContext added in v0.2.0

func NewHandlerContext(request *http.Request, responseWriter http.ResponseWriter, router *Router) *HandlerContext

func (*HandlerContext) ClearState added in v0.2.0

func (hc *HandlerContext) ClearState(key string)

func (*HandlerContext) ErrorForStatus added in v0.2.0

func (hc *HandlerContext) ErrorForStatus(status int) RoutingError

func (*HandlerContext) FirstError added in v0.2.0

func (hc *HandlerContext) FirstError() RoutingError

func (*HandlerContext) GetState added in v0.2.0

func (hc *HandlerContext) GetState(key string) interface{}

func (*HandlerContext) GetStateInt added in v0.3.1

func (hc *HandlerContext) GetStateInt(key string) int

func (*HandlerContext) GetStateString added in v0.3.1

func (hc *HandlerContext) GetStateString(key string) string

func (*HandlerContext) HasError added in v0.2.0

func (hc *HandlerContext) HasError() bool

func (*HandlerContext) HasErrorForStatus added in v0.2.0

func (hc *HandlerContext) HasErrorForStatus(status int) bool

func (*HandlerContext) SetState added in v0.2.0

func (hc *HandlerContext) SetState(key string, value interface{})

type Match

type Match struct {
	Node          *Node
	Params        map[string][]string
	CatchAllValue string
	ParentMatch   *Match
}

Match represents a matched node in the tree

func NewMatch

func NewMatch(node *Node) *Match

NewMatch creates a new Match instance

func NewMatchWithParent

func NewMatchWithParent(node *Node, parentMatch *Match) *Match

NewMatchWithParent creates a new instance of a match that passes down the values from the parent match

func (*Match) String

func (match *Match) String() string

type MatchCandidate

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

MatchCandidate is a helper class for matching path components

func NewMatchCandidate

func NewMatchCandidate(path string) MatchCandidate

NewMatchCandidate creates a new match candidate instance and initializes if for the first part

func NoMatchCandidate

func NoMatchCandidate() MatchCandidate

NoMatchCandidate represents an empty MatchCandidate

func (MatchCandidate) HasRemainingCandidates

func (mc MatchCandidate) HasRemainingCandidates() bool

HasRemainingCandidates returns true if the MatchCandidate has more candidate parts

func (MatchCandidate) IsNoMatch

func (mc MatchCandidate) IsNoMatch() bool

IsNoMatch returns true if the MatchCandidate equals the NoMatchCandidate value

func (MatchCandidate) NextCandidate

func (mc MatchCandidate) NextCandidate() MatchCandidate

NextCandidate returns the next MatchCandidate in the full path

type Matcher

type Matcher struct {
	LogMatchTime       bool
	FallbackToCatchAll bool
	// contains filtered or unexported fields
}

Matcher is the global matching engine

func NewMatcher

func NewMatcher(router *Router) *Matcher

NewMatcher creates a new instance of the Matcher

func (*Matcher) MatchPathToRoute

func (m *Matcher) MatchPathToRoute(method string, path string, req *http.Request) *Match

MatchPathToRoute attempts to match the given path to a registered Route

type Node

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

Node - tree node to store route information

func (*Node) HasChildren

func (node *Node) HasChildren() bool

HasChildren - returns true if the Node has 1 or more sub-Nodes

func (*Node) RouteForMethod

func (node *Node) RouteForMethod(method string) *Route

RouteForMethod - returns the route that was defined for the method or nil if no route is defined

func (*Node) String

func (node *Node) String() string

String - the string representation of the object when printing

type Parameters added in v0.2.0

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

func NewParametersWithMap added in v0.2.0

func NewParametersWithMap(paramsMap map[string][]string) *Parameters

func (*Parameters) Get added in v0.2.0

func (p *Parameters) Get(key string) []interface{}

func (*Parameters) GetFirstString added in v0.2.0

func (p *Parameters) GetFirstString(key string) string

func (*Parameters) GetInt added in v0.2.0

func (p *Parameters) GetInt(key string) int

func (*Parameters) GetInts added in v0.2.0

func (p *Parameters) GetInts(key string) []int

func (*Parameters) GetStrings added in v0.2.0

func (p *Parameters) GetStrings(key string) []string

type Route

type Route struct {
	Method     string
	Path       string
	PathFormat string
	Handler    ContextHandler
	Meta       map[string]interface{}
	Info       map[string]interface{}
}

Route stores all the information about a route

func NewRoute

func NewRoute(method string, path string) *Route

NewRoute creates a new Route instance

func NewRouteWithMeta

func NewRouteWithMeta(method string, path string, meta map[string]interface{}) *Route

NewRouteWithMeta creates a new Route instance with meta values

func (*Route) Describe

func (rte *Route) Describe(description string) *Route

Describe allows you to add a description of the route for other developers

func (*Route) Handle

func (rte *Route) Handle(handlerFunc ContextHandler) *Route

Handle adds a ContextHandler to the Route

func (*Route) HandleFunc

func (rte *Route) HandleFunc(handlerFunc ContextHandlerFunc) *Route

HandleFunc adds a ContextHandlerFunc to the Route

func (*Route) IsRoot

func (rte *Route) IsRoot() bool

IsRoot returns true if the Route path is '/'

type RouteCache

type RouteCache struct {

	// Entries - ordered list of cache entries
	Entries []CacheEntry

	// MaxEntries - maximum number of items permitted in the cache
	MaxEntries int

	// ReorderOnAccess - move the last accessed item to the top
	ReorderOnAccess bool
	// contains filtered or unexported fields
}

RouteCache - temporary storage for routes

func NewRouteCache

func NewRouteCache() *RouteCache

NewRouteCache - creates a new default RouteCache

func (*RouteCache) Clear

func (rc *RouteCache) Clear()

Clear - reset the cache

func (*RouteCache) Get

func (rc *RouteCache) Get(path string) CacheEntry

Get - fetch a cache entry (if exists)

func (*RouteCache) Put

func (rc *RouteCache) Put(path string, entry CacheEntry)

Put - add an item to the route cache

func (*RouteCache) PutRoute

func (rc *RouteCache) PutRoute(path string, route *Route)

PutRoute - add a route into the route cache

type RouteComponentType

type RouteComponentType int

RouteComponentType - route component types NOTE: variables will be stripped out / replaced so we dont track them

const (
	// ComponentTypeFixed - a fixed path component
	ComponentTypeFixed RouteComponentType = 1 << iota
	// ComponentTypeWildcard - a wildcard path component
	ComponentTypeWildcard
	// ComponentTypeCatchAll - catch all route component
	ComponentTypeCatchAll
)

type Router

type Router struct {

	// ShouldCacheMatchedRoutes - if true then any matched routes should be cached
	// according to the path they were matched to
	ShouldCacheMatchedRoutes bool
	// contains filtered or unexported fields
}

Router is the main routing class

func NewRouter

func NewRouter() *Router

NewRouter - creates a new default instance of the Router type

func (*Router) Add

func (r *Router) Add(method string, routePath string) *Route

Add creates a new Route and registers the instance within the Router

func (*Router) AddBundle added in v0.2.0

func (r *Router) AddBundle(bundle Bundle)

func (*Router) AddFilter

func (r *Router) AddFilter(filter Filter)

AddFilter adds a filter to the list of pre-process filters

func (*Router) AddStatic

func (r *Router) AddStatic(staticRoot string)

AddStatic registers a directory to serve static files

func (*Router) AddStaticWithPrefix

func (r *Router) AddStaticWithPrefix(staticRoot string, prefix string)

AddStaticWithPrefix registers a directory to serve static files. prefix value will be added at matching

func (*Router) GET added in v0.2.0

func (r *Router) GET(routePath string) *Route

Add creates a new Route using the GET method and registers the instance within the Router

func (*Router) Group added in v0.2.0

func (r *Router) Group(prefix string) *Group

Group creates a logical grouping point for a collection of routes. All routes under the group will have the group prefix appended to them.

func (*Router) HC added in v0.2.2

func (r *Router) HC(handlers ...ChainHandler) Chain

HC is syntactic sugar for NewChain

func (*Router) NewChain added in v0.2.0

func (r *Router) NewChain(handlers ...ChainHandler) Chain

NewChain - returns a new chain with the current router attached

func (*Router) NewMatcher

func (r *Router) NewMatcher() *Matcher

NewMatcher returns a new matcher for the given Router

func (*Router) POST added in v0.2.0

func (r *Router) POST(routePath string) *Route

Add creates a new Route using the POST method and registers the instance within the Router

func (*Router) PUT added in v0.2.0

func (r *Router) PUT(routePath string) *Route

Add creates a new Route using the PUT method and registers the instance within the Router

func (*Router) PrintRoutes

func (r *Router) PrintRoutes()

PrintRoutes prints route registration information

func (*Router) PrintTreeInfo

func (r *Router) PrintTreeInfo()

PrintTreeInfo prints debugging information about all registered Routes

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)

func (*Router) SetAlwaysUseFirstMatch added in v0.2.0

func (r *Router) SetAlwaysUseFirstMatch(alwaysUseFirst bool)

SetAlwaysUseFirstMatch - Will the router always return the first match regardless of whether it fully meets all the criteria?

func (*Router) SetDebugLevel

func (r *Router) SetDebugLevel(debugLevel DebugLevel)

SetDebugLevel - enables or disables Debug mode

func (*Router) SetErrorHandler

func (r *Router) SetErrorHandler(statusCode int, handler ContextHandler)

SetErrorHandler configures a ContextHandler to handle all errors for the supplied status code

func (*Router) SetGlobalHandler

func (r *Router) SetGlobalHandler(method string, handler ContextHandler)

SetGlobalHandler configures a ContextHandler to handle all requests for a given method

func (*Router) SetMethodNotAllowedIsError added in v0.2.0

func (r *Router) SetMethodNotAllowedIsError(isError bool)

SetMethodNotAllowedIsError - Will the router fail when it encounters a defined route that matches, but does not have a definition for the requested http method?

func (*Router) SetRouterErrorHandler added in v0.2.0

func (r *Router) SetRouterErrorHandler(handler ContextHandler)

SetRouterErrorHandler configures a ContextHandler to handle all general router errors (i.e.: non-network related)

func (*Router) SetStringVariable

func (r *Router) SetStringVariable(variable string, value string)

SetStringVariable adds a string variable value for substitution

func (*Router) Use

func (r *Router) Use(routes ...*Route) []*Route

Use registers one or more Route instances within the Router

type RouterErrorCode added in v0.2.0

type RouterErrorCode int

error codes RouterErrorCode - type used to represent an error in the routing request

const (
	// RouterError - a non-specific router error
	RouterGenericErrorCode RouterErrorCode = 1 << iota
	// RouterContentError - a router static content error
	RouterContentErrorCode
	// ChainHadError - a router chain dispatched an error
	ChainGenericErrorCode
)
const ErrorCodePanic RouterErrorCode = 777

ErrorCodePanic - error code used when recovering from a panic

type RoutingError added in v0.2.0

type RoutingError struct {
	StatusCode int
	ErrorCode  RouterErrorCode
	Error      error
	Message    string
	Info       ErrorInfoMap
}

func EmptyRoutingError added in v0.2.0

func EmptyRoutingError() RoutingError

type StaticLocation

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

StaticLocation is a holder for static location information

type Tree

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

Tree - storage for routes

func NewTree

func NewTree() *Tree

NewTree - creates a new Tree instance

func (*Tree) AddRouteToTree

func (t *Tree) AddRouteToTree(route *Route, variables map[string]string)

AddRouteToTree - splits the route into Nodes and adds them to the tree

func (*Tree) NewNode

func (t *Tree) NewNode(part string, parent *Node) *Node

NewNode - creates a new Node instance and appends it to the tree

Jump to

Keyboard shortcuts

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