Router
Package router provides a manager to add public and secure routes based on a http.Handler
or http.HandlerFunc
.
Specific Action<->HTTP Method mapping can be defined.
Middleware can be added for each route or globally for all secured routes.
Files or directories can be added.
The PATTERN
, PARAMS
, ACTION
and (ALLOWED
HTTP Methods - only on OPTIONS) will be added as request context.
Usage
Inspired by the database/sql
, this module is based on providers. You have to import the needed provider with a dash in
front:
This will only call the init function(s) of the package(s) and will register itself. For a full list of all available
providers, see the providers section.
import "github.com/patrickascher/gofer/router"
import _ "github.com/patrickascher/gofer/router/httprouter" // example for the julienschmidt http router
New
The New function requires two arguments. First the name of the registered provider and a provider configuration. Each provider will have different configuration settings, please see the providers section for more details.
// get a new router instance.
routerManager,err := router.New(router.JSROUTER,nil)
AllowHTTPMethod
Can be used to disable one or more HTTP methods globally. By Default: TRACE
and CONNECT
are disabled.
// will disable globally HTTP GET for any routes.
err = routerManager.AllowHTTPMethod(http.MethodGet,false)
SetSecureMiddleware
Middleware(s) can be added. They will automatically apply to the AddSecureRoute
(s).
routerManager.SetSecureMiddleware(mw)
SetFavicon
Sets the fav icon. The pattern is /favicon.ico
. If the source does not exist, an error will return.
err := routerManager.SetFavicon("assets/img/favicon.ico")
AddPublicFile
The first argument is the pattern, and the second one is the source. The pattern must begin with a /
. If the pattern
already exists, or the source does not exist, an error will return.
err := routerManager.AddPublicFile("/robot.txt","assets/static/robot.txt")
AddPublicDir
The first argument is the pattern, and the second one is the source. Directories are not allowed on pattern root
level /
. The pattern must begin with a /
. If the pattern already exists, or the source does not exist, an error will
return.
err := routerManager.AddPublicDir("/images","assets/img")
AddPublicRoute
A route can be added to the router. Please see the route section for more details.
err := routerManager.AddPublicRoute(router.NewRoute("/login", handleFunc))
AddSecureRoute
A secure route can be added to the router. Please see the route section for more details. The route
secure variable will be set to true
If no secure middleware(s) are defined, an error will return.
err := routerManager.AddSecureRoute(router.NewRoute("/admin", handleFunc))
Routes
All defined routes of the router will return.
routes := routerManager.Routes()
RouteByPattern
The route by the given pattern will return. If the pattern does not exist, an error will return.
routes := routerManager.RouteByPattern("/favicon.ico")
Handler
Returns the http.Handler
.
handler := routerManager.Handler()
SetNotFound
Set a custom handler for all routes which can not be found.
routerManager.SetNotFound(hanlder)
Route
A new route can be created with router.NewRoute(pattern string, handler interface{}, mapping ...Mapping)
.
patter
: If the pattern already exists, an error will return.
handler
can be of type http.Handler
or http.HandlerFunc
. If it is nil
or any other type, an error will return.
A action name mapping is required on http.Handler
. Mappings can be defined optionally on http.HandlerFunc
. By
default, all allowed HTTP methods of the router, will be mapped.
A Mapping instance can be created with router.NewMapping(methods []string, action interface{}, mw *middleware)
.
The methods
are any HTTP methods which should be mapped to the pattern. If its nil, all allowed HTTP methods of the
router manager will be added.
The action
can be of the type string
or func
. If the type is func
, the function name will be set as string on
runtime. The action string will be added as request context.
If set, the middlewares
will be added to the route.
For each pattern, any HTTP method must be unique, otherwise an error will return.
route := router.NewRoute("/public2", handleFunc, router.NewMapping([]string{http.MethodGet}, "View", nil), router.NewMapping([]string{http.MethodPUt}, "Create", nil))
Middleware
All pre-defined middleware:
Logger
Provides a middleware for the logger.Manager
. The logged information is remoteAddr, HTTP Method, URL, Proto, HTTP
Status, Response size and requested time. On HTTP status < 400 a log.Info()
will be called otherwise log.Error()
.
Info
The logger middleware should used before all other middlewares, otherwise the request time will be incorrect.
// the middleware
mw := router.NewMiddleware(middleware.NewLogger(logManager).MW)
JWT
Provides a middleware to check against a JWT token. If the JWT token is invalid a http.StatusUnauthorized
will return.
If the JWT token is expired it will be re-generated if allowed. In such case, the request header will be manipulated if a refresh happens, so that there is the new refresh token as REFRESH
cookie and the old one as REFRESH_OLD
.
There are two callback functions. CallbackGenerate
for manipulating the claim before its signed. CallbackRefresh
to
check if the refresh token is still valid, against a custom logic.
The claim will be set as request context with the key jwt.CLAIM
.
A claim struct is provided and can be embedded into a custom struct.
cfg := jwt.Config{
Alg: jwt.HS512,
Issuer: "authserver",
Audience: "client",
Subject: "auth",
Expiration: 5*time.Minute,
SignKey: "secret",
RefreshToken: jwt.RefreshConfig{Expiration: 30*24*time.Hour}
}
claim := jwt.Claim{}
jwt := jwt.New(cfg,claim);
jwt.CallbackRefresh = func(http.ResponseWriter, *http.Request, Claimer){return nil} // your logic
jwt.CallbackGenerate = func(http.ResponseWriter, *http.Request, Claimer){return nil} // your logic
// the middleware
mw := router.NewMiddleware(jwt.MW)
RBAC
Provides a role based access control list. It is build on top of the JWT middleware.
A RoleService must be set, to check against the custom logic. Simply implement the RoleService
interface. The
arguments pattern
HTTP method
and claim
will be passed to the Allowed
function.
Info
The JWT middleware must be set before the RBAC middleware.
roleService := CustomService{};
rbac := middleware.NewRbac(roleService)
// the middleware
mw := router.NewMiddleware(jwt.MW, rbac.MW)
Providers
All pre-defined providers:
JSROUTER
A wrapper for httprouter.
Name:
router.JSROUTER
Options:
no options are available at the moment.
Usage:
import "github.com/patrickascher/gofer/router"
import _ "github.com/patrickascher/gofer/router/jsrouter"
r,err := router.New(router.JSROUTER,nil)
Create your own provider
To create your own provider, you have to implement the router.Provider
interface.
// Provider interface.
type Provider interface {
// Handler must return the mux for http/server.
Handler() http.Handler
// custom NotFound handler can be set.
SetNotFound(http.Handler)
// AddRoute to the router.
AddRoute(Route) error
// AddPublicDir to the router.
// The source is already checked if it exists.
AddPublicDir(url string, path string) error
// AddPublicFile to the router
// The source is already checked if it exists.
AddPublicFile(url string, path string) error
}
Use the init
function to register your provider.
The registered value must be of the type func(m Manager, options interface{}) (router.Provider, error)
.
// init register your config provider
func init() {
//...
err := router.Register("my-provider",New)
if err != nil {
log.Fatal(err)
}
}
func New(m Manager, options interface{}) (router.Provider, error){
//...
return provider,nil
}
Usage
import "github.com/patrickascher/gofer/router"
import _ "your/repo/router/yourProvider"
err := router.New("my-provider", options)