app

package
v2.0.0-beta.8 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2025 License: MIT Imports: 8 Imported by: 0

Documentation

Index

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

type Ctx = ctx.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

type ErrorHandler func(ctx.Ctx, error)

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

type Handler func(ctx.Ctx) error

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

type Middleware func(Handler) Handler

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
	}
}

Jump to

Keyboard shortcuts

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