Documentation
¶
Index ¶
- type App
- type Ctx
- type DefaultApp
- func (a *DefaultApp) ANY(path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) DELETE(path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) ErrorHandler() ErrorHandler
- func (a *DefaultApp) GET(path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) Group(prefix string, mw ...Middleware) *Group
- func (a *DefaultApp) HEAD(path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) Handle(method, path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) HandleHTTP(method, path string, h http.Handler)
- func (a *DefaultApp) Logger() *slog.Logger
- func (a *DefaultApp) MethodNotAllowedHandler() http.Handler
- func (a *DefaultApp) Mount(path string, h http.Handler)
- func (a *DefaultApp) NotFoundHandler() http.Handler
- func (a *DefaultApp) OPTIONS(path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) PATCH(path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) POST(path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) PUT(path string, h Handler, mws ...Middleware)
- func (a *DefaultApp) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (a *DefaultApp) SetErrorHandler(h ErrorHandler)
- func (a *DefaultApp) SetLogger(l *slog.Logger)
- func (a *DefaultApp) SetMethodNotAllowedHandler(h http.Handler)
- func (a *DefaultApp) SetNotFoundHandler(h http.Handler)
- func (a *DefaultApp) Static(prefix, dir string)
- func (a *DefaultApp) StaticDirs(prefix string, dirs ...string)
- func (a *DefaultApp) Use(mw ...Middleware)
- type ErrorHandler
- type Group
- func (g *Group) DELETE(p string, h Handler, mws ...Middleware)
- func (g *Group) GET(p string, h Handler, mws ...Middleware)
- func (g *Group) Group(prefix string, mw ...Middleware) *Group
- func (g *Group) HEAD(p string, h Handler, mws ...Middleware)
- func (g *Group) OPTIONS(p string, h Handler, mws ...Middleware)
- func (g *Group) PATCH(p string, h Handler, mws ...Middleware)
- func (g *Group) POST(p string, h Handler, mws ...Middleware)
- func (g *Group) PUT(p string, h Handler, mws ...Middleware)
- func (g *Group) Use(mw ...Middleware)
- type Handler
- type Middleware
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type App ¶
type App interface {
// Middleware management
Use(mw ...Middleware)
// Route registration
GET(path string, h Handler, mws ...Middleware)
POST(path string, h Handler, mws ...Middleware)
PUT(path string, h Handler, mws ...Middleware)
PATCH(path string, h Handler, mws ...Middleware)
DELETE(path string, h Handler, mws ...Middleware)
OPTIONS(path string, h Handler, mws ...Middleware)
HEAD(path string, h Handler, mws ...Middleware)
ANY(path string, h Handler, mws ...Middleware)
Handle(method, path string, h Handler, mws ...Middleware)
// HTTP integration and mounting
ServeHTTP(w http.ResponseWriter, r *http.Request)
HandleHTTP(method, path string, h http.Handler)
Mount(path string, h http.Handler)
Static(prefix, dir string)
StaticDirs(prefix string, dirs ...string)
// Grouping
Group(prefix string, mw ...Middleware) *Group
// Logging
SetLogger(l *slog.Logger)
Logger() *slog.Logger
// Error/NotFound/MethodNotAllowed handlers
SetErrorHandler(h ErrorHandler)
SetNotFoundHandler(h http.Handler)
SetMethodNotAllowedHandler(h http.Handler)
// Getters for handlers (mirrors Set*). Useful when holding App as an interface.
ErrorHandler() ErrorHandler
NotFoundHandler() http.Handler
MethodNotAllowedHandler() http.Handler
}
App defines the public surface of the router/app, suitable for mocking. Implemented by *DefaultApp.
func New ¶
func New() App
New creates a new DefaultApp with sensible defaults and returns it as the App interface.
Defaults include:
- JSON slog logger at info level to stdout
- 404 and 405 handlers wired to the internal router hooks
- MethodNotAllowed handling enabled on the router
- Context pooling for performance
Example:
func main() {
a := app.New()
a.GET("/hello/:name", func(c app.Ctx) error {
return c.String(http.StatusOK, "hello "+c.Param("name"))
})
_ = http.ListenAndServe(":8080", a)
}
type Ctx ¶
Ctx is re-exported for package-local convenience in tests and internal APIs. External users can refer to this type as app.Ctx or ctx.Ctx.
type DefaultApp ¶
type DefaultApp struct {
OnError ErrorHandler // error handler
NotFound http.Handler // handler for 404 Not Found
MethodNA http.Handler // handler for 405 Method Not Allowed
// contains filtered or unexported fields
}
DefaultApp is the main application/router for flash. It implements http.Handler, manages routing, middleware, error handling, and logger configuration.
Performance note: a sync.Pool is used for context reuse to minimize allocations in the hot path. Each request acquires a fresh ctx.DefaultContext from the pool and returns it after completion. This pattern is safe for concurrent use and reduces GC pressure.
func (*DefaultApp) ANY ¶
func (a *DefaultApp) ANY(path string, h Handler, mws ...Middleware)
ANY registers a handler for all common HTTP methods (GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD) on the given path. Optionally accepts route-specific middleware.
Example:
a.ANY("/webhook", Webhook)
func (*DefaultApp) DELETE ¶
func (a *DefaultApp) DELETE(path string, h Handler, mws ...Middleware)
DELETE registers a handler for HTTP DELETE requests on the given path. Optionally accepts route-specific middleware.
Example:
a.DELETE("/users/:id", DeleteUser, Audit)
func (*DefaultApp) ErrorHandler ¶
func (a *DefaultApp) ErrorHandler() ErrorHandler
Getters mirror the setters and are useful when holding App as an interface. They expose the currently configured handlers without exporting struct fields.
func (*DefaultApp) GET ¶
func (a *DefaultApp) GET(path string, h Handler, mws ...Middleware)
GET registers a handler for HTTP GET requests on the given path. Optionally accepts route-specific middleware.
Example:
a := app.New()
a.GET("/health", func(c app.Ctx) error { return c.String(http.StatusOK, "ok") })
Example (with route params and middleware):
a.GET("/users/:id", ShowUser, Auth)
// order: global -> Auth -> ShowUser; handler sees c.Param("id")
func (*DefaultApp) Group ¶
func (a *DefaultApp) Group(prefix string, mw ...Middleware) *Group
Group creates a new route group with the given prefix and optional middleware. Routes registered on the group inherit the prefix and group middleware.
The prefix is normalized and joined using internal helpers so that either absolute or relative segments work as expected (e.g., "/api" + "/v1" -> "/api/v1").
Example:
api := a.Group("/api", Auth)
api.GET("/health", Health)
// registers handler at path "/api/health" with middleware: global -> Auth
Example (adding middleware later):
api := a.Group("/api")
api.GET("/ping", Ping) // only global middleware applies
api.Use(Auth)
api.GET("/me", Me) // now global -> Auth applies
func (*DefaultApp) HEAD ¶
func (a *DefaultApp) HEAD(path string, h Handler, mws ...Middleware)
HEAD registers a handler for HTTP HEAD requests on the given path. Optionally accepts route-specific middleware. Mirrors GET semantics but does not write a response body.
Example:
a.HEAD("/health", HeadHealth)
func (*DefaultApp) Handle ¶
func (a *DefaultApp) Handle(method, path string, h Handler, mws ...Middleware)
Handle registers a handler for a custom HTTP method on the given path. Optionally accepts route-specific middleware. Use this for less common methods (e.g., PROPFIND, REPORT) or extension methods used by specialized clients.
Example:
a.Handle("REPORT", "/dav/resource", HandleReport)
func (*DefaultApp) HandleHTTP ¶
func (a *DefaultApp) HandleHTTP(method, path string, h http.Handler)
HandleHTTP mounts a net/http.Handler on a specific HTTP method and path. This enables interoperability with standard library handlers or third-party http.Handler implementations without adapting to app.Handler.
The handler receives the raw http.ResponseWriter and *http.Request. Use this method when you want to pass through to an existing handler as-is.
Example:
a := app.New()
a.HandleHTTP(http.MethodGet, "/metrics", promhttp.Handler())
_ = http.ListenAndServe(":8080", a)
func (*DefaultApp) Logger ¶
func (a *DefaultApp) Logger() *slog.Logger
Logger returns the configured application logger, or slog.Default if none is set. Prefer enriching this logger with request-scoped fields in middleware using ctx.ContextWithLogger.
func (*DefaultApp) MethodNotAllowedHandler ¶
func (a *DefaultApp) MethodNotAllowedHandler() http.Handler
func (*DefaultApp) Mount ¶
func (a *DefaultApp) Mount(path string, h http.Handler)
Mount mounts a net/http.Handler for all common HTTP methods (GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD) under the given path.
This is useful for mounting sub-routers or third-party handlers that already implement routing internally (e.g., a GraphQL handler, an admin console).
Example (mounting a sub-router):
sr := http.NewServeMux()
sr.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("ok")) })
a := app.New()
a.Mount("/admin", sr)
// Now /admin/health is served by sr for GET/POST/PUT/PATCH/DELETE/OPTIONS/HEAD
func (*DefaultApp) NotFoundHandler ¶
func (a *DefaultApp) NotFoundHandler() http.Handler
func (*DefaultApp) OPTIONS ¶
func (a *DefaultApp) OPTIONS(path string, h Handler, mws ...Middleware)
OPTIONS registers a handler for HTTP OPTIONS requests on the given path. Optionally accepts route-specific middleware. Useful for CORS preflight handling.
Example:
a.OPTIONS("/users", Preflight)
func (*DefaultApp) PATCH ¶
func (a *DefaultApp) PATCH(path string, h Handler, mws ...Middleware)
PATCH registers a handler for HTTP PATCH requests on the given path. Optionally accepts route-specific middleware. Typically used for partial updates.
Example:
a.PATCH("/users/:id", UpdateUserEmail)
func (*DefaultApp) POST ¶
func (a *DefaultApp) POST(path string, h Handler, mws ...Middleware)
POST registers a handler for HTTP POST requests on the given path. Optionally accepts route-specific middleware. Commonly used for creating resources.
Example:
a.POST("/users", CreateUser, CSRF)
func (*DefaultApp) PUT ¶
func (a *DefaultApp) PUT(path string, h Handler, mws ...Middleware)
PUT registers a handler for HTTP PUT requests on the given path. Optionally accepts route-specific middleware. Typically used for full resource replacement.
Example:
a.PUT("/users/:id", ReplaceUser)
func (*DefaultApp) ServeHTTP ¶
func (a *DefaultApp) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler by delegating to the internal router. Typically you pass the App itself to http.ListenAndServe.
Example:
_ = http.ListenAndServe(":8080", a)
func (*DefaultApp) SetErrorHandler ¶
func (a *DefaultApp) SetErrorHandler(h ErrorHandler)
Configuration setters. These set the error, not found, and method-not-allowed handlers used by the app.
func (*DefaultApp) SetLogger ¶
func (a *DefaultApp) SetLogger(l *slog.Logger)
SetLogger sets the application logger used by middlewares and utilities. If not set, Logger() falls back to slog.Default().
Example:
a.SetLogger(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})))
func (*DefaultApp) SetMethodNotAllowedHandler ¶
func (a *DefaultApp) SetMethodNotAllowedHandler(h http.Handler)
func (*DefaultApp) SetNotFoundHandler ¶
func (a *DefaultApp) SetNotFoundHandler(h http.Handler)
func (*DefaultApp) Static ¶
func (a *DefaultApp) Static(prefix, dir string)
Static serves files from a directory under a URL prefix for GET and HEAD requests. This is a convenience that delegates to StaticDirs with a single directory.
Example:
a := app.New()
a.Static("/assets", "./public")
// Serves GET/HEAD /assets/* from files under ./public
func (*DefaultApp) StaticDirs ¶
func (a *DefaultApp) StaticDirs(prefix string, dirs ...string)
StaticDirs serves files from multiple directories under the same URL prefix for GET and HEAD requests. Directories are searched in order; the first existing file is served. This mirrors frameworks like Fiber where multiple folders can back the same route.
The prefix is normalized and must end with a trailing slash; a catch-all pattern "*filepath" is registered under that prefix. The underlying handler strips the prefix before serving from the merged filesystem.
Security considerations:
- Ensure you only expose directories meant to be public
- Avoid serving dotfiles if not intended (http.FileServer will serve them)
- Consider setting appropriate Cache-Control headers via middleware
Examples:
// Single directory equivalent to Static("/assets", "./public")
a.StaticDirs("/assets", "./public")
// Multiple directories: look in ./public first, then ./themes/default
a.StaticDirs("/assets", "./public", "./themes/default")
// /assets/logo.png will be served from the first directory that contains it
func (*DefaultApp) Use ¶
func (a *DefaultApp) Use(mw ...Middleware)
Use registers global middleware, applied to all routes in the order added. Route-specific middleware passed at registration time is applied after global middleware.
Example:
a.Use(Log, Recover)
a.GET("/", Home, Auth) // execution order: Log -> Recover -> Auth -> Home
type ErrorHandler ¶
ErrorHandler handles errors returned from handlers. It is called when a handler (or middleware) returns a non-nil error. Implementations should translate the error into an HTTP response and log it.
Example:
func myErrorHandler(c app.Ctx, err error) {
logger := ctx.LoggerFromContext(c.Context())
logger.Error("request failed", "err", err)
_ = c.String(http.StatusInternalServerError, "internal error")
}
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
Group defines a group of routes with a common URL prefix and optional middleware. Groups allow modular organization of related routes and sharing of cross-cutting concerns such as authentication, logging, or rate limiting.
A Group is typically created from an App (a *DefaultApp) via (*DefaultApp).Group. Nested groups may be created from an existing Group using (*Group).Group.
Middleware Order:
- Global middleware (registered with App.Use) runs first in registration order
- Then parent group middleware, then child group middleware (outer -> inner)
- Then route-specific middleware (when passed during route registration)
- Finally the route handler
Example (organization and middleware stacking):
a := app.New()
a.Use(Log) // global
api := a.Group("/api", Auth) // /api with Auth
v1 := api.Group("/v1", Audit) // /api/v1 with Auth then Audit
v1.GET("/users/:id", ShowUser, Trace) // order: Log -> Auth -> Audit -> Trace -> ShowUser
The final path for a group's route is joinPath(parent.prefix, group.prefix, routePath). Paths are normalized (e.g., duplicate slashes collapsed, trailing slash rules follow internal cleanPath/joinPath semantics). Route parameters (":id") defined in the path are available to handlers via c.Param("id").
func (*Group) DELETE ¶
func (g *Group) DELETE(p string, h Handler, mws ...Middleware)
DELETE registers a handler for HTTP DELETE requests on the group's prefix + path. Optionally accepts route-specific middleware.
Example:
api.DELETE("/users/:id", DeleteUser, Audit)
func (*Group) GET ¶
func (g *Group) GET(p string, h Handler, mws ...Middleware)
GET registers a handler for HTTP GET requests on the group's prefix + path. Optionally accepts route-specific middleware.
Example:
api := a.Group("/api")
api.GET("/health", Health)
Example (with params and route-specific middleware):
api.GET("/users/:id", ShowUser, Trace)
// handler sees c.Param("id"); order: global -> group -> Trace -> ShowUser
func (*Group) Group ¶
func (g *Group) Group(prefix string, mw ...Middleware) *Group
Group creates a nested route group inheriting the parent's prefix and middleware. Additional middleware can be provided for the nested group.
Example:
api := a.Group("/api", Auth)
v1 := api.Group("/v1", Audit)
v1.GET("/users", ListUsers) // path: /api/v1/users; order: global -> Auth -> Audit -> handler
Example (deep nesting and route-specific middleware):
admin := v1.Group("/admin", AdminOnly)
admin.GET("/stats", Stats, Trace)
// order: global -> Auth -> Audit -> AdminOnly -> Trace -> Stats
func (*Group) HEAD ¶
func (g *Group) HEAD(p string, h Handler, mws ...Middleware)
HEAD registers a handler for HTTP HEAD requests on the group's prefix + path. Optionally accepts route-specific middleware. Mirrors GET semantics but returns no response body.
Example:
api.HEAD("/health", HeadHealth)
func (*Group) OPTIONS ¶
func (g *Group) OPTIONS(p string, h Handler, mws ...Middleware)
OPTIONS registers a handler for HTTP OPTIONS requests on the group's prefix + path. Optionally accepts route-specific middleware. Useful for CORS preflight handling.
Example:
api.OPTIONS("/users", Preflight)
func (*Group) PATCH ¶
func (g *Group) PATCH(p string, h Handler, mws ...Middleware)
PATCH registers a handler for HTTP PATCH requests on the group's prefix + path. Optionally accepts route-specific middleware. Typically used for partial updates of resources.
Example:
api.PATCH("/users/:id", UpdateUserEmail)
func (*Group) POST ¶
func (g *Group) POST(p string, h Handler, mws ...Middleware)
POST registers a handler for HTTP POST requests on the group's prefix + path. Optionally accepts route-specific middleware. Commonly used for creating resources.
Example:
api.POST("/users", CreateUser, CSRF)
// order: global -> group -> CSRF -> CreateUser
func (*Group) PUT ¶
func (g *Group) PUT(p string, h Handler, mws ...Middleware)
PUT registers a handler for HTTP PUT requests on the group's prefix + path. Optionally accepts route-specific middleware. Typically used for full updates of resources.
Example:
api.PUT("/users/:id", ReplaceUser)
func (*Group) Use ¶
func (g *Group) Use(mw ...Middleware)
Use adds middleware to the group. Middleware is applied in the order added.
Example:
api := a.Group("/api")
api.Use(Auth, Audit)
api.GET("/users", ListUsers) // order: global -> Auth -> Audit -> handler
type Handler ¶
Handler is the function signature for goflash route handlers (and the output of composed middleware). It receives a request context and returns an error.
Returning a non-nil error delegates to the App's ErrorHandler, allowing a single place to translate errors into HTTP responses and logs.
Example:
func hello(c app.Ctx) error {
name := c.Param("name")
if name == "" {
return fmt.Errorf("missing name")
}
return c.String(http.StatusOK, "hello "+name)
}
type Middleware ¶
Middleware transforms a Handler, enabling composition of cross-cutting concerns such as logging, authentication, rate limiting, etc.
Middleware registered via Use is applied in the order added; route-specific middleware is applied after global middleware and before the route handler. A middleware can decide to short-circuit by returning without calling next.
Example (logging middleware):
func Log(next app.Handler) app.Handler {
return func(c app.Ctx) error {
start := time.Now()
err := next(c)
logger := ctx.LoggerFromContext(c.Context())
logger.Info("handled",
"method", c.Method(),
"path", c.Path(),
"status", c.StatusCode(),
"dur", time.Since(start),
)
return err
}
}