Documentation
¶
Index ¶
- func LoggingMiddleware(next http.Handler) http.Handler
- func NonceFromContext(ctx context.Context) string
- func RenderError(w http.ResponseWriter, r *http.Request, err error)
- func Serve(views embed.FS, opts ...Option)
- type App
- func (app *App) Controller(name string, controller Controller)
- func (app *App) Func(name string, fn any)
- func (app *App) Method(controller any, methodName string, bouncer Bouncer) http.Handler
- func (app *App) RenderToString(name string, data any) (string, error)
- func (app *App) Serve(templateName string, bouncer Bouncer) *View
- type BaseController
- func (c *BaseController) IntParam(name string, defaultValue int) int
- func (c *BaseController) IsHTMX(r *http.Request) bool
- func (c *BaseController) QueryParam(name, defaultValue string) string
- func (c *BaseController) Redirect(w http.ResponseWriter, r *http.Request, path string)
- func (c *BaseController) Refresh(w http.ResponseWriter, r *http.Request)
- func (c *BaseController) Render(w http.ResponseWriter, r *http.Request, templateName string, data any)
- func (c *BaseController) RenderError(w http.ResponseWriter, r *http.Request, err error)
- func (c *BaseController) Setup(app *App)
- func (c *BaseController) Stream(w http.ResponseWriter) *Streamer
- type BaseEmailer
- type Bouncer
- type Controller
- type Emailer
- type Middleware
- type Option
- func WithController(name string, controller Controller) Option
- func WithEmailer(emailer Emailer) Option
- func WithFunc(name string, fn any) Option
- func WithHealthPath(path string) Option
- func WithMiddleware(mw Middleware) Option
- func WithValue(name string, value any) Option
- func WithViews(views fs.FS) Option
- type Streamer
- type View
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func LoggingMiddleware ¶
LoggingMiddleware returns middleware that logs all requests.
func NonceFromContext ¶
NonceFromContext returns the per-request nonce, or empty string if none.
func RenderError ¶
func RenderError(w http.ResponseWriter, r *http.Request, err error)
RenderError renders an error message (returns 200 for HTMX compatibility). In production (ENV=production), internal error details are hidden to prevent information leakage. Full errors are logged for debugging.
Types ¶
type App ¶
type App struct {
Emailer
// ScriptFunc generates the frontend <script> tags with a nonce.
// Set by the frontend controller; called per-request in render().
ScriptFunc func(nonce string) template.HTML
// contains filtered or unexported fields
}
App is the main application container
func New ¶
New creates an App and applies the given options. This triggers controller Setup functions, useful for build-time tasks.
func (*App) Controller ¶
func (app *App) Controller(name string, controller Controller)
Controller registers a controller with the application. If the controller has a Setup method, it will be called.
func (*App) Func ¶
Func registers a template function with the application. This must be called before templates are parsed (typically in options).
func (*App) Method ¶
Method creates a handler that calls a controller method with optional bouncer. Validates the method exists and has the correct signature at registration time.
func (*App) RenderToString ¶
RenderToString renders a template to a string. For partials (already in base templates), use just the filename: "live-time.html" For views, use the path relative to views/: "index.html" or "admin/dashboard.html"
type BaseController ¶
BaseController is the base type for all controllers. Embed this in your controller structs.
func (*BaseController) IntParam ¶
func (c *BaseController) IntParam(name string, defaultValue int) int
IntParam returns an integer query parameter with a default value
func (*BaseController) IsHTMX ¶
func (c *BaseController) IsHTMX(r *http.Request) bool
IsHTMX returns true if the request is from HTMX
func (*BaseController) QueryParam ¶
func (c *BaseController) QueryParam(name, defaultValue string) string
QueryParam returns a query parameter with a default value
func (*BaseController) Redirect ¶
func (c *BaseController) Redirect(w http.ResponseWriter, r *http.Request, path string)
Redirect sends a redirect response (HX-Location for HTMX, HTTP redirect otherwise)
func (*BaseController) Refresh ¶
func (c *BaseController) Refresh(w http.ResponseWriter, r *http.Request)
Refresh sends an HX-Refresh header to reload the page
func (*BaseController) Render ¶
func (c *BaseController) Render(w http.ResponseWriter, r *http.Request, templateName string, data any)
Render renders a template with optional data
func (*BaseController) RenderError ¶
func (c *BaseController) RenderError(w http.ResponseWriter, r *http.Request, err error)
RenderError delegates to the standalone RenderError function. Kept for backward compatibility with existing controllers.
func (*BaseController) Setup ¶
func (c *BaseController) Setup(app *App)
Setup initializes the controller with the application. Override this in your controller to register routes.
func (*BaseController) Stream ¶
func (c *BaseController) Stream(w http.ResponseWriter) *Streamer
Stream creates a new SSE streamer for real-time updates. Sets appropriate headers and returns a Streamer for sending events.
Example:
func (c *HomeController) Live(w http.ResponseWriter, r *http.Request) {
stream := c.Stream(w)
for {
select {
case <-r.Context().Done():
return
case msg := <-updates:
stream.Send("messages", "<div>"+msg+"</div>")
}
}
}
Template usage with HTMX SSE extension:
<div hx-ext="sse" sse-connect="/live" sse-swap="messages">
Loading...
</div>
type BaseEmailer ¶
type BaseEmailer struct {
// contains filtered or unexported fields
}
BaseEmailer provides common email template rendering functionality. Embed this in your emailer implementations.
type Bouncer ¶
Bouncer is a function that gates route access. Returns true to allow the request, false to block it.
type Controller ¶
type Controller interface {
Handle(r *http.Request) Controller
}
Controller is the interface that controllers implement. The Handle method receives the request and returns a controller instance that can be used by templates to access controller methods.
type Middleware ¶
Middleware wraps an http.Handler (e.g. for request interception).
func NonceMiddleware ¶
func NonceMiddleware() Middleware
NonceMiddleware generates a cryptographic nonce per request and stores it in the request context. Retrieve with NonceFromContext.
func SecurityHeaders ¶
func SecurityHeaders() Middleware
SecurityHeaders returns a middleware that sets security response headers on every response. CSP uses a per-request nonce from NonceMiddleware.
The CSP policy:
- script-src uses nonce + strict-dynamic (CDN scripts loaded by nonce'd scripts inherit trust)
- 'unsafe-inline' is a CSP2 fallback, ignored by CSP3 browsers when a nonce is present
- style-src allows 'unsafe-inline' because Tailwind CSS Browser runtime needs it
- frame-ancestors 'none' replaces X-Frame-Options in CSP-aware browsers
type Option ¶
type Option func(*App)
Option configures the application
func WithController ¶
func WithController(name string, controller Controller) Option
WithController registers a controller with the application. Takes (name, controller) from factory function like controllers.Home().
func WithEmailer ¶
WithEmailer sets the emailer implementation
func WithHealthPath ¶
WithHealthPath sets the path for the auto-registered health endpoint. Defaults to "/health" if not set.
func WithMiddleware ¶
func WithMiddleware(mw Middleware) Option
WithMiddleware adds a middleware to the handler chain. Middlewares are applied in order, with the last-added wrapping outermost.
type Streamer ¶
type Streamer struct {
// contains filtered or unexported fields
}
Streamer provides Server-Sent Events (SSE) streaming. Use with HTMX's SSE extension for real-time updates.
Create via c.Stream(w), which sets SSE headers and flushes immediately.
Three ways to send events:
Send(event, data): Named event — client listens via sse-swap="event". Use for HTMX targets where the event name selects which DOM element to swap.
SendData(data): Default (unnamed) "message" event — client receives via onmessage or sse-swap="message". Use for simple data push (e.g., JSON payloads consumed by JavaScript, not HTMX swap targets).
Render(event, template, data): Named event with server-rendered HTML. Renders a Go template to string and sends it as an SSE event. Use when the server produces the final HTML (the common HTMX pattern). Newlines in rendered HTML are replaced with spaces (safe for HTML, required by SSE spec).
func (*Streamer) Render ¶
Render renders a template and sends it via SSE. For partials, use just the filename (e.g., "live-time.html"). Newlines are replaced with spaces (safe for HTML).
Example:
stream.Render("time", "live-time.html", time.Now().Format("15:04:05"))