Web-framework for web-applications. The biggest implementation of kern is currently written for node.js.
As I needed a framework in go for developing kubernetes controllers, I decided to start this minimalistic port.
A simple demo application can be found in the demo-repository
package main
import (
"github.com/GeraldWodni/kern.go"
"github.com/GeraldWodni/kern.go/view"
)
func main() {
app := kern.New(":5000")
view.Globals["AppName"] = "kern.go demo app"
app.Router.Get("/", view.NewHandler( "index.gohtml" ) )
app.Run()
}
kern.go main include, see the demo repository for a full demo.
type Kern struct {
Router *router.Router
Hierarchy *hierarchy.Hierarchy
BindAddr string
}
func New(bindAddr string, hierarchyPrefixes []string) (kern *Kern)
Kern instance hosted on bindAddr
Hint: mounts /favicon.ico
, /css
, /js
,
/images
, /files
from /default/*
func (kern *Kern) Run()
Run http.ListenAndServe
for Kern
instance
Routers provide simple separation of mountable modules. This provides a reusability of code, i.e. a webshop can run standalone when mounted under "/", or by mounted under "/shop" of a full featured website.
func Err(res http.ResponseWriter, err error)
Render an error
as status code 500
type Route struct {
Method string
Path string
Handler RouteHandler
}
type RouteHandler func(res http.ResponseWriter, req *http.Request, next RouteNext)
Extend the (res, req) handler interface with a resume-route callback
func ErrHandler(err error) RouteHandler
Wrapper for Err, provides a RouteHandler for convenience see view/view.go for example usage
type RouteNext func()
Callback function if a RouteHandler was a match but routing should continue
type Router struct {
// optionally identify router per name
Name string
MountPoint string
Routes []Route
NotFoundHandler RouteHandler
}
func New(mountPoint string) (router *Router)
New router with it's mountpoint fixed. Hint: use this function when creating mountable modules which return their own router.
func (router *Router) Add(method string, path string, handler RouteHandler)
Add RouteHandler with explicit method mounted at path
. Use All
, Get
OR
Post
unless crazy methods are required
func (router *Router) All(path string, handler RouteHandler)
Match all methods on path
func (router *Router) Get(path string, handler RouteHandler)
Match all GET
requests on path
func (router *Router) HierarchyDir(h *hierarchy.Hierarchy, path string)
Serve file after hierarchy lookup
func (router *Router) Mount(subRouter *Router)
Mount router created by New
on existing router i.e. app.Router
func (router *Router) NewMounted(mountPoint string) (subRouter *Router)
Wrapper to create a mounted router. Hint: use when implementing a simple tree-navigation in an app
func (router *Router) Post(path string, handler RouteHandler)
Match all POST
requests on path
func (router *Router) ServeHTTP(res http.ResponseWriter, req *http.Request)
Gets called by http
, not to be used by app
func (router *Router) StaticDir(path string, dir string)
FileServer
wrapper for exposing the contents of dir
under path
func (router *Router) StaticFile(path string, contentType string, filename string)
Provide a static file. Kern automatically provides a favicon via this function:
kern.Router.StaticFile( "/favicon.ico", "image/x-icon", "./default/images/favicon.ico" )
func (router *Router) StaticHtml(path string, html string)
Send html
with the correct mimetype Example:
router.StaticHtml( '<html><body><h1>Oh noes!, something went terribly wrong</h1></body></html>' )
Hint: usefull for static error messages which need a bit of formatting, use
view.View
for all else.
func (router *Router) StaticText(path string, text string)
Send text
with the correct mimetype
Provides a wrapper class around html.template
. Loaded templates are kept in
cache but watched with fsnotify
which invalidates the cache and forces a read
on the next Render
var Globals = make(InterfaceMap)
Available to all templates, i.e. `{{.Globals.FooBar}}
func Handler(view ViewInterface) (routeHandler router.RouteHandler)
Wrapper for Render using a router.RouteHandler
func NewCssHandler(filenames ...string) (routeHandler router.RouteHandler)
func NewHtmlHandler(filenames ...string) (routeHandler router.RouteHandler)
Load a view and directly return router.RouteHandler
Hint: useful for views
without locals
func NewTextHandler(contentType string, filenames ...string) (routeHandler router.RouteHandler)
type FuncMap map[string]any
Pipeline functions exposed to template
type HtmlView struct {
View
Template *htmlTemplate.Template
}
func NewHtml(filenames ...string) (view *HtmlView, err error)
Creates a new View
which is immidiatly loaded and watched for file changes
func (view *HtmlView) Render(res http.ResponseWriter, req *http.Request, next router.RouteNext, locals interface{})
Render view using Globals
as well as values passed via locals
type InterfaceMap map[string]interface{}
type Message struct {
Type string // TODO: make enum?
Title string
Text string
}
type TextView struct {
View
Template *textTemplate.Template
}
func NewText(contentType string, filenames ...string) (view *TextView, err error)
func (view *TextView) Render(res http.ResponseWriter, req *http.Request, next router.RouteNext, locals interface{})
type View struct {
Filenames []string
ReloadRequired bool
TemplateName string
ContentType string
}
type ViewInterface interface {
Render(http.ResponseWriter, *http.Request, router.RouteNext, interface{})
// contains filtered or unexported methods
}
type ViewTemplate interface {
Execute(w io.Writer, data any) error
ExecuteTemplate(w io.Writer, template string, data any) error
}
Hierarchical lookup for pathes. Instead of a hardcoded path, a list of directories is traversed to allow for easy extension and subvolume-mounting.
type Hierarchy struct {
Prefixes []string
}
func New(prefixes []string) (hierarchy *Hierarchy, err error)
Creates a new Hierarchy
with a list of prefixes; hint: default
is
automatically appended.
func (hierarchy *Hierarchy) Exists(prefix string, suffix string) (ok bool)
func (hierarchy *Hierarchy) Lookup(suffixes ...string) (filename string, ok bool)
lookup with optional fail
func (hierarchy *Hierarchy) LookupDirectory(suffixes ...string) (filenames []string, ok bool)
load contents of folder and allow hierarchical overwriting
func (hierarchy *Hierarchy) LookupFatal(suffixes ...string) (filename string)
lookup with fatal fail
func (hierarchy *Hierarchy) LookupFile(prefix string, suffix string) (filename string, ok bool)
provides a redis connection wrapper around each request
Hint: this module is implitly loaded by session.
func Of(req *http.Request) (rdb redis.Conn, ok bool)
get redis connection from request-context i.e. redis.Of( req ).Do( "SET", "Lana", "aaaaaaaaa" )
sanitize input - all unwanted characters are removed
HINT: always use theese functions for receiving user input. Only access the input directly if you are certain there is no other way.
func Address(t string) string
func Allocnum(t string) string
func Alnum(t string) string
func AlnumList(t string) string
func Alpha(t string) string
func Boolean(t string) string
func Color(t string) string
func DateTime(t string) string
func Decimal(t string) string
func Email(t string) string
func EscapedLink(t string) string
func Filename(t string) string
func Filepath(t string) string
func Hex(t string) string
func Id(t string) string
func Int(t string) string
func Link(t string) string
func LinkItem(t string) string
func LinkList(t string) string
func Password(t string) string
func Post(req *http.Request, filter Filter) string
Get PostValue from request, using the lowecase filter-name as name
func PostName(req *http.Request, name string, filter Filter) string
Get PostValue from request and sanizie it )
func Raw(t string) string
func SingleLine(t string) string
func Telephone(t string) string
func Text(t string) string
func Uint(t string) string
func Url(t string) string
func Username(t string) string
type Filter func(text string) string
session management - via a single cookie
func Destroy(res http.ResponseWriter, req *http.Request)
Destroy existing session
func NewSessionId() (sessionId string)
type Session struct {
Id string
Values map[string]string
// logged in username
Username string
LoggedIn bool
Permissions string
}
func New(res http.ResponseWriter, req *http.Request) (session *Session)
Start a new session
func Of(req *http.Request) (session *Session, ok bool)
get session for request-context i.e. session.Of( req ).Id
module interfaces - implement proper module for easy extension of kern.go
see session.sessionModule
for a simple example
func ExecuteEndRequest(res http.ResponseWriter, req *http.Request)
Called internally by Router
func ExecuteStartRequest(res http.ResponseWriter, reqIn *http.Request) (reqOut *http.Request, ok bool)
Called internally by Router
func RegisterRequest(requestModule Request)
type Request interface {
// Executed upon request start. Returns a new `http.request` - usually `reqIn` wrapped in a new `Context`.
// if `ok` is false, all further request handling will be stopped, handler needs to write `res` himself
StartRequest(res http.ResponseWriter, reqIn *http.Request) (reqOut *http.Request, ok bool)
// Executed upon exit of request
EndRequest(res http.ResponseWriter, req *http.Request)
}
Request-modules are invoked upon every request
environment variable based login credentials (useful for docker images in i.e. kubernetes)
login - handler rejects further routing and displays login form
static credentials, recommended only for developement purposes
func NewEnvironmentCredentialChecker() *envCredentials
Load users from environment variables, the prefixes are KERN_USER_
and
KERN_PREMISSIONS_
. Example values: KERN_USER_bob=soopersecret
KERN_PERMISSIONS_bob=view,add,peel
For usage call: login.Register( login.NewEnvironmentCredentialChecker() )
func NewStaticCredentials(username string, password string, permissions string) *staticCredentials
Static credentials (recommended for developement purposes only) Example: ``
func PermissionReqired(path string, permission string) (loginRouter *router.Router)
Stops all further routing when permission
is not held by current session.
Displays loginView
(login.gohtml
) when no session is found
func Register(credentialChecker CredentialChecker)
type CredentialChecker interface {
Check(username string, password string) (permissions string, ok bool)
}
type User struct {
Username string
Password string
Permissions string
}
user management (static)
func (user *User) String() string
logout - router destroys any session and warns otherwise
func Logout(path string) (logoutRouter *router.Router)
Stops all further routing when permission
is not held by current session.
Displays logoutView
(logout.gohtml
) when no session is found
Colorful logger interface which UTC timestampts and multi-level severity
var Colors = map[string]string{
"Reset": "\x1b[0m",
"Black": "\x1b[30m",
"Red": "\x1b[31m",
"Green": "\x1b[32m",
"Yellow": "\x1b[33m",
"Blue": "\x1b[34m",
"Magenta": "\x1b[35m",
"Cyan": "\x1b[36m",
"White": "\x1b[37m",
"BrightBlack": "\x1b[1;30m",
"BrightRed": "\x1b[1;31m",
"BrightGreen": "\x1b[1;32m",
"BrightYellow": "\x1b[1;33m",
"BrightBlue": "\x1b[1;34m",
"BrightMagenta": "\x1b[1;35m",
"BrightCyan": "\x1b[1;36m",
"BrightWhite": "\x1b[1;37m",
}
var LevelDebug = Colors["BrightBlack"]
var LevelError = Colors["BrightRed"]
var LevelFatal = Colors["Red"]
var LevelInfo = Colors["BrightBlue"]
var LevelSection = Colors["BrightMagenta"]
var LevelSubSection = Colors["BrightCyan"]
var LevelSuccess = Colors["BrightGreen"]
var LevelWarning = Colors["BrightYellow"]
func Debug(a ...interface{})
func Debugf(format string, a ...interface{})
func Error(a ...interface{})
func Errorf(format string, a ...interface{})
func Fatal(a ...interface{})
func Info(a ...interface{})
func Infof(format string, a ...interface{})
func Log(level string, a ...interface{})
func Logf(level string, format string, a ...interface{})
func Section(a ...interface{})
func Sectionf(format string, a ...interface{})
func SubSection(a ...interface{})
func SubSectionf(format string, a ...interface{})
func Success(a ...interface{})
func Successf(format string, a ...interface{})
func Warning(a ...interface{})
func Warningf(format string, a ...interface{})