Documentation
¶
Overview ¶
Package forge provides a simple, opinionated framework for building B2B micro-SaaS applications in Go.
Forge is designed around the principle of "no magic" — it uses explicit, readable code with no reflection or service containers. The framework provides a thin orchestration layer while keeping business logic in plain Go handlers.
Quick Start ¶
Create a new application with New(), configure it with options, and pass it to Run():
app := forge.New(
forge.AppConfig{},
forge.WithHandlers(
handlers.NewAuth(repo),
handlers.NewPages(repo),
),
)
if err := forge.Run(
forge.RunConfig{},
forge.WithFallback(app),
forge.WithRunLogger(logger),
); err != nil {
log.Fatal(err)
}
Context as context.Context ¶
The Context interface embeds context.Context, so it can be passed directly to any function that expects a standard library context:
func (h *Handler) getUser(c forge.Context) error {
// c satisfies context.Context — pass it to DB calls, HTTP clients, etc.
user, err := h.repo.GetUser(c, userID)
if err != nil {
return err
}
return c.JSON(200, user)
}
Identity and Authentication ¶
Context provides convenience methods for checking the current user. These are shortcuts over the session system and return safe defaults when no session is configured:
func (h *Handler) showProfile(c forge.Context) error {
if !c.IsAuthenticated() {
return c.Redirect(http.StatusSeeOther, "/login")
}
user, err := h.repo.GetUser(c, c.UserID())
if err != nil {
return err
}
// Only allow users to edit their own profile
canEdit := c.IsCurrentUser(user.ID)
return c.Render(http.StatusOK, views.Profile(user, canEdit))
}
Sessions ¶
Enable server-side session management with WithSession. Sessions auto-create on first access via SessionGet or SessionSet:
app := forge.New(
forge.AppConfig{},
forge.WithSession(postgresStore,
forge.WithSessionTTL(7 * 24 * time.Hour),
forge.WithMaxSessionsPerUser(3),
forge.WithSessionFingerprint(
forge.FingerprintCookie,
forge.FingerprintWarn,
),
),
)
Use SessionGet and SessionSet for type-safe access:
func (h *Handler) login(c forge.Context) error {
if err := forge.SessionSet(c, "user_id", user.ID); err != nil {
return err
}
if err := forge.SessionSet(c, "login_time", time.Now()); err != nil {
return err
}
return c.Redirect(http.StatusSeeOther, "/dashboard")
}
func (h *Handler) dashboard(c forge.Context) error {
userID, ok := forge.SessionGet[string](c, "user_id")
if !ok {
return c.Redirect(http.StatusSeeOther, "/login")
}
// Use userID...
return c.Render(http.StatusOK, views.Dashboard())
}
Role-Based Access Control (RBAC) ¶
Configure permissions with WithRoles. The role extractor is called lazily on the first [Context.Can] call and cached for the request:
app := forge.New(
forge.AppConfig{},
forge.WithRoles(
forge.RolePermissions{
"admin": {"users.read", "users.write", "billing.manage"},
"member": {"users.read"},
},
func(c forge.Context) string {
return forge.ContextValue[string](c, roleKey{})
},
),
)
Check permissions in handlers:
func (h *Handler) deleteUser(c forge.Context) error {
if !c.Can("users.write") {
return forge.ErrForbidden("You do not have permission")
}
return h.repo.DeleteUser(c, forge.Param[string](c, "id"))
}
Type-Safe Parameter Helpers ¶
Generic helper functions provide type-safe access to URL and query parameters. They use strconv for conversion and return zero values on parse failure:
func (h *Handler) listItems(c forge.Context) error {
page := forge.QueryDefault[int](c, "page", 1)
limit := forge.QueryDefault[int](c, "limit", 20)
items, err := h.repo.ListItems(c, page, limit)
if err != nil {
return err
}
return c.JSON(http.StatusOK, items)
}
func (h *Handler) getItem(c forge.Context) error {
id := forge.Param[int64](c, "id")
item, err := h.repo.GetItem(c, id)
if err != nil {
return err
}
return c.JSON(http.StatusOK, item)
}
Supported types: ~string, ~int, ~int64, ~float64, ~bool.
Handlers ¶
Handlers implement the Handler interface to declare routes:
type AuthHandler struct {
repo *repository.Queries
}
func NewAuth(repo *repository.Queries) *AuthHandler {
return &AuthHandler{repo: repo}
}
func (h *AuthHandler) Routes(r forge.Router) {
r.GET("/login", h.showLogin)
r.POST("/login", h.handleLogin)
r.POST("/logout", h.handleLogout)
}
func (h *AuthHandler) showLogin(c forge.Context) error {
return c.Render(http.StatusOK, views.LoginPage())
}
Middleware ¶
Middleware wraps handlers to add cross-cutting concerns:
func RequestLogger(log *slog.Logger) forge.Middleware {
return func(next forge.HandlerFunc) forge.HandlerFunc {
return func(c forge.Context) error {
start := time.Now()
err := next(c)
log.Info("request",
"method", c.Request().Method,
"path", c.Request().URL.Path,
"duration", time.Since(start),
"error", err,
)
return err
}
}
}
Add middleware globally with WithMiddleware:
app := forge.New(
forge.AppConfig{},
forge.WithMiddleware(
RequestLogger(logger),
middlewares.RequestID(middlewares.RequestIDConfig{}),
middlewares.Recover(middlewares.RecoverConfig{}),
),
)
Built-In Middlewares ¶
The middlewares package provides common functionality:
- RequestID: Adds request tracking IDs
- Recover: Handles panics gracefully
- I18n: Internationalization and localization
- JWT: Token-based authentication
- CSRF: Cross-site request forgery protection
- RateLimit: Request rate limiting
- AuditLog: Request and action logging
Jobs and Background Processing ¶
Enable background job processing with River integration:
app := forge.New(
forge.AppConfig{},
forge.WithJobs(pgxPool,
job.Config{
Workers: 2,
},
job.WithTask(EmailTask{}),
job.WithScheduledTask(CleanupTask{}),
),
)
Define tasks using structural typing:
type EmailTask struct{}
func (EmailTask) Name() string { return "send_email" }
func (EmailTask) Handle(ctx context.Context, p struct{ Email string }) error {
// Send email...
return nil
}
Enqueue jobs from handlers:
func (h *Handler) signup(c forge.Context) error {
// ...validation...
err := c.Enqueue("send_email",
struct{ Email string }{Email: user.Email},
job.WithQueue("emails"),
job.WithScheduledIn(1*time.Minute),
)
if err != nil {
return err
}
return c.Redirect(http.StatusSeeOther, "/signup/confirm")
}
File Storage ¶
Enable S3-compatible file storage:
s, err := storage.New(storage.Config{
Endpoint: "s3.amazonaws.com",
AccessKey: os.Getenv("AWS_ACCESS_KEY_ID"),
SecretKey: os.Getenv("AWS_SECRET_ACCESS_KEY"),
Bucket: "myapp-uploads",
Region: "us-east-1",
})
if err != nil {
log.Fatal(err)
}
app := forge.New(
forge.AppConfig{},
forge.WithStorage(s),
)
Upload and download files from handlers:
func (h *Handler) uploadAvatar(c forge.Context) error {
info, err := c.Upload("avatar",
storage.WithPrefix("avatars"),
storage.WithValidation(
storage.MaxSize(5*1024*1024),
storage.ImageOnly(),
),
)
if err != nil {
return err
}
// Save info.Key to database
return c.JSON(http.StatusOK, map[string]string{
"url": info.URL,
})
}
Server-Sent Events (SSE) ¶
Stream events to clients using the channel-based SSE API. The framework handles headers, keepalive, and flushing:
func (h *Handler) streamEvents(c forge.Context) error {
ch := make(chan forge.SSEEvent)
go func() {
defer close(ch)
for {
select {
case <-c.Done():
return
case event := <-eventChan:
ch <- forge.SSEString("message", event.Data)
}
}
}()
return c.SSE(ch)
}
Multi-Domain Routing ¶
For applications that need host-based routing, compose multiple Apps with Run():
api := forge.New(
forge.AppConfig{BaseDomain: "acme.com"},
forge.WithHandlers(handlers.NewAPIHandler()),
)
website := forge.New(
forge.AppConfig{BaseDomain: "acme.com"},
forge.WithHandlers(handlers.NewLandingHandler()),
)
if err := forge.Run(
forge.RunConfig{Address: ":8080"},
forge.WithDomain("api.acme.com", api),
forge.WithDomain("*.acme.com", website),
forge.WithRunLogger(logger),
); err != nil {
log.Fatal(err)
}
Error Handling ¶
Return HTTPError from handlers to set the status code and error details:
func (h *Handler) getUser(c forge.Context) error {
user, err := h.repo.GetUser(c, id)
if err == sql.ErrNoRows {
return forge.ErrNotFound("User not found")
}
if err != nil {
return forge.ErrInternal("Failed to fetch user")
}
return c.JSON(http.StatusOK, user)
}
Customize error response handling with WithErrorHandler:
app := forge.New(
forge.AppConfig{},
forge.WithErrorHandler(func(c forge.Context, err error) error {
if httpErr := forge.AsHTTPError(err); httpErr != nil {
return c.JSON(httpErr.StatusCode(), httpErr)
}
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "Something went wrong",
})
}),
)
Shutdown ¶
The application handles SIGINT/SIGTERM for graceful shutdown. Register cleanup functions with WithShutdownHook:
if err := forge.Run(
forge.RunConfig{Address: ":8080"},
forge.WithFallback(app),
forge.WithShutdownHook(func(ctx context.Context) error {
return pool.Close()
}),
); err != nil {
log.Fatal(err)
}
Configuration ¶
Load configuration from environment variables with LoadConfig:
type Config struct {
DatabaseURL string `env:"DATABASE_URL,required"`
Port string `env:"PORT" envDefault:":8080"`
Debug bool `env:"DEBUG"`
}
var cfg Config
if err := forge.LoadConfig(&cfg); err != nil {
log.Fatal(err)
}
Testing ¶
For testing, use httptest.NewServer with the app:
app := forge.New(
forge.AppConfig{},
forge.WithHandlers(myHandler),
)
ts := httptest.NewServer(app.Router())
defer ts.Close()
resp, err := http.Get(ts.URL + "/path")
if err != nil {
t.Fatal(err)
}
// Assert response...
Index ¶
- Constants
- Variables
- func ContextValue[T any](c Context, key any) T
- func GetCSRFToken(c Context) string
- func GetJWTClaims[T any](c Context) *T
- func GetLanguage(c Context) string
- func GetRateLimitInfo(c Context) *ratelimit.Info
- func GetRequestID(c Context) string
- func GetTranslator(c Context) *i18n.Translator
- func IsHTTPError(err error) bool
- func IsPanicError(err error) bool
- func LoadConfig(dst any) error
- func Param[T ~string | ~int | ~int64 | ~float64 | ~bool](c Context, name string) T
- func Query[T ~string | ~int | ~int64 | ~float64 | ~bool](c Context, name string) T
- func QueryDefault[T ~string | ~int | ~int64 | ~float64 | ~bool](c Context, name string, defaultValue T) T
- func RequestIDExtractor() logger.ContextExtractor
- func Run(cfg RunConfig, opts ...RunOption) error
- func SessionGet[T any](c Context, key string) (T, bool)
- func SessionSet[T any](c Context, key string, value T) error
- func SetAuditMetadata(c Context, key, value string)
- func T(c Context, key string, placeholders ...i18n.M) string
- func Tn(c Context, key string, n int, placeholders ...i18n.M) string
- type App
- type AppConfig
- type AuditEntry
- type AuditOption
- type AuditStore
- type CSRFConfig
- type CSRFOption
- type CheckFunc
- type Component
- type Context
- type ErrorHandler
- type Extractor
- type ExtractorSource
- func FromAcceptLanguage(available []string) ExtractorSource
- func FromBearerToken() ExtractorSource
- func FromCookie(name string) ExtractorSource
- func FromCookieEncrypted(name string) ExtractorSource
- func FromCookieSigned(name string) ExtractorSource
- func FromForm(name string) ExtractorSource
- func FromHeader(name string) ExtractorSource
- func FromParam(name string) ExtractorSource
- func FromQuery(name string) ExtractorSource
- func FromSession(key string) ExtractorSource
- type FingerprintMode
- type FingerprintStrictness
- type HTTPError
- func AsHTTPError(err error) *HTTPError
- func ErrBadRequest(message string, opts ...HTTPErrorOption) *HTTPError
- func ErrConflict(message string, opts ...HTTPErrorOption) *HTTPError
- func ErrForbidden(message string, opts ...HTTPErrorOption) *HTTPError
- func ErrInternal(message string, opts ...HTTPErrorOption) *HTTPError
- func ErrNotFound(message string, opts ...HTTPErrorOption) *HTTPError
- func ErrServiceUnavailable(message string, opts ...HTTPErrorOption) *HTTPError
- func ErrTooManyRequests(message string, opts ...HTTPErrorOption) *HTTPError
- func ErrUnauthorized(message string, opts ...HTTPErrorOption) *HTTPError
- func ErrUnprocessable(message string, opts ...HTTPErrorOption) *HTTPError
- func NewHTTPError(code int, message string) *HTTPError
- type HTTPErrorOption
- type Handler
- type HandlerFunc
- type HealthCheckOption
- type I18nOption
- type JWTClaimsKey
- type JWTOption
- type LanguageKey
- type Middleware
- type Option
- func WithCookieConfig(cfg cookie.Config) Option
- func WithCustomLogger(l *slog.Logger) Option
- func WithErrorHandler(h ErrorHandler) Option
- func WithHandlers(h ...Handler) Option
- func WithHealthChecks(checks ...HealthCheckOption) Option
- func WithJobEnqueuer(pool *pgxpool.Pool, opts ...job.EnqueuerOption) Option
- func WithJobWorker(pool *pgxpool.Pool, cfg job.Config, opts ...job.Option) Option
- func WithJobs(pool *pgxpool.Pool, cfg job.Config, opts ...job.Option) Option
- func WithLogger(component string, extractors ...logger.ContextExtractor) Option
- func WithMethodNotAllowedHandler(h HandlerFunc) Option
- func WithMiddleware(mw ...Middleware) Option
- func WithNotFoundHandler(h HandlerFunc) Option
- func WithRoles(permissions RolePermissions, extractor RoleExtractorFunc) Option
- func WithSSEKeepAlive(d time.Duration) Option
- func WithSession(store SessionStore, opts ...SessionOption) Option
- func WithStaticFiles(pattern string, fsys fs.FS, subDir string) Option
- func WithStorage(s storage.Storage) Option
- type PanicError
- type Permission
- type RateLimitOption
- type ResponseWriter
- type RoleExtractorFunc
- type RolePermissions
- type Router
- type RunConfig
- type RunOption
- func WithContext(ctx context.Context) RunOption
- func WithDomain(pattern string, app *App) RunOption
- func WithFallback(app *App) RunOption
- func WithRunLogger(l *slog.Logger) RunOption
- func WithShutdownHook(fn func(context.Context) error) RunOption
- func WithStartupHook(fn func(context.Context) error) RunOption
- type SSEEvent
- type Session
- type SessionOption
- type SessionStore
- type TranslatorKey
- type ValidationErrors
Constants ¶
const ( // FingerprintDisabled disables fingerprint generation and validation. FingerprintDisabled = internal.FingerprintDisabled // FingerprintCookie uses default settings, excludes IP. Best for most web apps. FingerprintCookie = internal.FingerprintCookie // FingerprintJWT uses minimal fingerprint, excludes Accept headers. FingerprintJWT = internal.FingerprintJWT // FingerprintHTMX uses only User-Agent, avoids HTMX header variations. FingerprintHTMX = internal.FingerprintHTMX // FingerprintStrict includes IP address. WARNING: causes false positives. FingerprintStrict = internal.FingerprintStrict )
Fingerprint mode constants.
const ( // FingerprintWarn logs a warning but allows the session to continue. FingerprintWarn = internal.FingerprintWarn // FingerprintReject invalidates the session on fingerprint mismatch. FingerprintReject = internal.FingerprintReject )
Fingerprint strictness constants.
Variables ¶
var ( ErrCookieNotFound = cookie.ErrNotFound ErrCookieNoSecret = cookie.ErrNoSecret ErrCookieBadSecret = cookie.ErrBadSecret ErrCookieBadSig = cookie.ErrBadSig ErrCookieDecrypt = cookie.ErrDecrypt )
Cookie errors for checking return values.
var ( ErrSessionNotConfigured = internal.ErrSessionNotConfigured ErrSessionNotFound = internal.ErrSessionNotFound ErrSessionExpired = internal.ErrSessionExpired ErrSessionInvalidToken = internal.ErrSessionInvalidToken ErrSessionFingerprintMismatch = internal.ErrSessionFingerprintMismatch )
Session errors for checking return values.
var ( // SSEString creates a string SSE event. SSEString = internal.SSEString // SSEJSON creates a JSON SSE event. SSEJSON = internal.SSEJSON // SSETempl creates an HTML SSE event from a templ Component. SSETempl = internal.SSETempl // SSEComment creates an SSE comment (keepalive, etc.). SSEComment = internal.SSEComment // SSERetry creates an SSE retry directive. SSERetry = internal.SSERetry )
SSE event constructors
var ( WithSessionTTL = internal.WithSessionTTL WithMaxSessionsPerUser = internal.WithMaxSessionsPerUser WithSessionTouchThreshold = internal.WithSessionTouchThreshold WithSessionCookieName = internal.WithSessionCookieName WithSessionFingerprint = internal.WithSessionFingerprint WithSessionLogger = internal.WithSessionLogger )
Session option re-exports
var ( ErrJobNotConfigured = job.ErrNotConfigured ErrJobUnknownTask = job.ErrUnknownTask ErrJobInvalidPayload = job.ErrInvalidPayload ErrJobHealthcheckFailed = job.ErrHealthcheckFailed ErrJobPoolRequired = job.ErrPoolRequired )
Job errors for checking return values.
var ( ErrStorageNotConfigured = storage.ErrNotConfigured ErrStorageInvalidConfig = storage.ErrInvalidConfig ErrStorageEmptyFile = storage.ErrEmptyFile ErrStorageFileTooLarge = storage.ErrFileTooLarge ErrStorageFileTooSmall = storage.ErrFileTooSmall ErrStorageInvalidMIME = storage.ErrInvalidMIME ErrStorageNotFound = storage.ErrNotFound ErrStorageAccessDenied = storage.ErrAccessDenied ErrStorageUploadFailed = storage.ErrUploadFailed ErrStorageDeleteFailed = storage.ErrDeleteFailed ErrStoragePresignFailed = storage.ErrPresignFailed ErrStorageInvalidURL = storage.ErrInvalidURL ErrStorageDownloadFailed = storage.ErrDownloadFailed )
Storage errors for checking return values.
var ( WithCSRFTokenGenerator = middlewares.WithCSRFTokenGenerator WithCSRFErrorHandler = middlewares.WithCSRFErrorHandler WithCSRFSkipFunc = middlewares.WithCSRFSkipFunc )
CSRF option constructor re-exports
var ( WithRateLimitKeyFunc = middlewares.WithRateLimitKeyFunc WithRateLimitErrorHandler = middlewares.WithRateLimitErrorHandler WithRateLimitSkipFunc = middlewares.WithRateLimitSkipFunc )
Rate limit option constructor re-exports
var ( WithAuditLogger = middlewares.WithAuditLogger WithAuditSkipFunc = middlewares.WithAuditSkipFunc WithAuditActionFunc = middlewares.WithAuditActionFunc WithAuditResourceFunc = middlewares.WithAuditResourceFunc WithAuditMetadataFunc = middlewares.WithAuditMetadataFunc WithAuditTimeout = middlewares.WithAuditTimeout )
Audit option constructor re-exports
Functions ¶
func ContextValue ¶
ContextValue retrieves a typed value from the context. Returns the zero value of T if the key is not found or type assertion fails.
func GetCSRFToken ¶
GetCSRFToken extracts the CSRF token from the context. Returns an empty string if no token is set.
func GetJWTClaims ¶
GetJWTClaims extracts parsed JWT claims from the context. Returns nil if the JWT middleware is not applied or the type doesn't match.
func GetLanguage ¶
GetLanguage extracts the resolved language from the context. Returns an empty string if the I18n middleware is not used.
func GetRateLimitInfo ¶
GetRateLimitInfo returns the rate limit info stored in the context by the RateLimit middleware. Returns nil if the middleware was not applied or the request was skipped.
func GetRequestID ¶
GetRequestID extracts the request ID from the context. Returns an empty string if no request ID is set.
func GetTranslator ¶
func GetTranslator(c Context) *i18n.Translator
GetTranslator extracts the Translator from the context. Returns nil if the I18n middleware is not used.
func IsHTTPError ¶
IsHTTPError returns true if the error is an HTTPError.
func IsPanicError ¶
IsPanicError returns true if the error is a PanicError.
func LoadConfig ¶
LoadConfig parses environment variables into dst using struct tags. It loads .env from the working directory automatically. Struct fields use `env:"KEY"`, `envDefault:"value"`, and `envSeparator:","` tags to declare their bindings.
func Param ¶
Param retrieves a typed URL parameter from the request. Uses strconv for type conversion. Returns the zero value of T on parse error.
func Query ¶
Query retrieves a typed query parameter from the request. Uses strconv for type conversion. Returns the zero value of T on parse error.
func QueryDefault ¶
func QueryDefault[T ~string | ~int | ~int64 | ~float64 | ~bool](c Context, name string, defaultValue T) T
QueryDefault retrieves a typed query parameter with a default value. Returns defaultValue if the parameter is empty or cannot be parsed.
func RequestIDExtractor ¶
func RequestIDExtractor() logger.ContextExtractor
RequestIDExtractor returns a ContextExtractor for use with WithLogger. Automatically adds "request_id" to all log entries.
func Run ¶
Run starts a multi-domain HTTP server and blocks until shutdown. Use this for composing multiple Apps under different domain patterns.
func SessionGet ¶
SessionGet retrieves a typed value from the session. Returns (value, true) if found and type matches, (zero, false) otherwise.
Example:
func Handler(c forge.Context) error {
userID, ok := forge.SessionGet[string](c, "user_id")
if !ok {
return c.Redirect(http.StatusSeeOther, "/login")
}
// Use userID...
}
This automatically creates the session if it doesn't exist.
func SessionSet ¶
SessionSet stores a typed value in the session.
Example:
func LoginHandler(c forge.Context) error {
// After validating credentials...
if err := forge.SessionSet(c, "user_id", user.ID); err != nil {
return err
}
if err := forge.SessionSet(c, "login_time", time.Now()); err != nil {
return err
}
return c.Redirect(http.StatusSeeOther, "/dashboard")
}
This automatically creates the session if it doesn't exist and marks it dirty for saving.
func SetAuditMetadata ¶
SetAuditMetadata adds a key-value pair to the audit entry metadata. No-op if the AuditLog middleware is not applied.
Types ¶
type App ¶
App orchestrates the application lifecycle. It manages HTTP routing, middleware, and graceful shutdown.
type AuditEntry ¶
type AuditEntry = middlewares.Entry
AuditEntry represents a single audit log record.
func GetAuditEntry ¶
func GetAuditEntry(c Context) *AuditEntry
GetAuditEntry extracts the audit entry from the context. Returns nil if the AuditLog middleware is not applied.
type AuditOption ¶
type AuditOption = middlewares.AuditOption
AuditOption configures the AuditLog middleware.
type AuditStore ¶
type AuditStore = middlewares.Store
AuditStore defines the interface for persisting audit log entries.
type CSRFConfig ¶
type CSRFConfig = middlewares.CSRFConfig
CSRFConfig configures the CSRF middleware.
type CSRFOption ¶
type CSRFOption = middlewares.CSRFOption
CSRFOption configures runtime dependencies for the CSRF middleware.
type ErrorHandler ¶
type ErrorHandler = internal.ErrorHandler
ErrorHandler handles errors returned from handlers.
type Extractor ¶
Extractor tries multiple sources in order and returns the first match. Use with FromHeader, FromQuery, FromCookie, etc. to compose extraction chains.
func NewExtractor ¶
func NewExtractor(sources ...ExtractorSource) Extractor
NewExtractor creates an Extractor that tries the given sources in order. Returns the first non-empty value found.
type ExtractorSource ¶
type ExtractorSource = internal.ExtractorSource
ExtractorSource extracts a value from the request context. Returns the value and true if found, or ("", false) if not present.
func FromAcceptLanguage ¶
func FromAcceptLanguage(available []string) ExtractorSource
FromAcceptLanguage returns an ExtractorSource that parses the Accept-Language header and matches against the available languages.
func FromBearerToken ¶
func FromBearerToken() ExtractorSource
FromBearerToken returns an ExtractorSource that reads a Bearer token from the Authorization header. Uses case-insensitive prefix matching.
func FromCookie ¶
func FromCookie(name string) ExtractorSource
FromCookie returns an ExtractorSource that reads from a plain cookie.
func FromCookieEncrypted ¶
func FromCookieEncrypted(name string) ExtractorSource
FromCookieEncrypted returns an ExtractorSource that reads from an encrypted cookie.
func FromCookieSigned ¶
func FromCookieSigned(name string) ExtractorSource
FromCookieSigned returns an ExtractorSource that reads from a signed cookie.
func FromForm ¶
func FromForm(name string) ExtractorSource
FromForm returns an ExtractorSource that reads from a form field.
func FromHeader ¶
func FromHeader(name string) ExtractorSource
FromHeader returns an ExtractorSource that reads from a request header.
func FromParam ¶
func FromParam(name string) ExtractorSource
FromParam returns an ExtractorSource that reads from a URL parameter.
func FromQuery ¶
func FromQuery(name string) ExtractorSource
FromQuery returns an ExtractorSource that reads from a query parameter.
func FromSession ¶
func FromSession(key string) ExtractorSource
FromSession returns an ExtractorSource that reads from a session value. Tries string type assertion first, falls back to fmt.Sprint for non-string values.
type FingerprintMode ¶
type FingerprintMode = internal.FingerprintMode
FingerprintMode determines which fingerprint generation algorithm to use.
type FingerprintStrictness ¶
type FingerprintStrictness = internal.FingerprintStrictness
FingerprintStrictness determines behavior on fingerprint mismatch.
type HTTPError ¶
HTTPError represents an HTTP error with all data needed for rendering.
func AsHTTPError ¶
AsHTTPError extracts the HTTPError from an error if present. Returns nil if the error is not an HTTPError.
func ErrBadRequest ¶
func ErrBadRequest(message string, opts ...HTTPErrorOption) *HTTPError
ErrBadRequest creates a 400 Bad Request error.
func ErrConflict ¶
func ErrConflict(message string, opts ...HTTPErrorOption) *HTTPError
ErrConflict creates a 409 Conflict error.
func ErrForbidden ¶
func ErrForbidden(message string, opts ...HTTPErrorOption) *HTTPError
ErrForbidden creates a 403 Forbidden error.
func ErrInternal ¶
func ErrInternal(message string, opts ...HTTPErrorOption) *HTTPError
ErrInternal creates a 500 Internal Server Error.
func ErrNotFound ¶
func ErrNotFound(message string, opts ...HTTPErrorOption) *HTTPError
ErrNotFound creates a 404 Not Found error.
func ErrServiceUnavailable ¶
func ErrServiceUnavailable(message string, opts ...HTTPErrorOption) *HTTPError
ErrServiceUnavailable creates a 503 Service Unavailable error.
func ErrTooManyRequests ¶
func ErrTooManyRequests(message string, opts ...HTTPErrorOption) *HTTPError
ErrTooManyRequests creates a 429 Too Many Requests error.
func ErrUnauthorized ¶
func ErrUnauthorized(message string, opts ...HTTPErrorOption) *HTTPError
ErrUnauthorized creates a 401 Unauthorized error.
func ErrUnprocessable ¶
func ErrUnprocessable(message string, opts ...HTTPErrorOption) *HTTPError
ErrUnprocessable creates a 422 Unprocessable Entity error.
func NewHTTPError ¶
NewHTTPError creates a new HTTPError with the given status code and message.
type HTTPErrorOption ¶
type HTTPErrorOption = internal.HTTPErrorOption
HTTPErrorOption configures an HTTPError.
func WithDetail ¶
func WithDetail(detail string) HTTPErrorOption
WithDetail sets the extended description.
func WithErrorCode ¶
func WithErrorCode(code string) HTTPErrorOption
WithErrorCode sets the application-specific error code.
func WithRequestID ¶
func WithRequestID(id string) HTTPErrorOption
WithRequestID sets the request tracking ID.
type HandlerFunc ¶
type HandlerFunc = internal.HandlerFunc
HandlerFunc is the signature for route handlers.
type HealthCheckOption ¶
type HealthCheckOption = internal.HealthCheckOption
HealthCheckOption adds a readiness check to the health configuration.
func HealthCheck ¶
func HealthCheck(name string, fn CheckFunc) HealthCheckOption
HealthCheck creates a named readiness check for use with WithHealthChecks.
type I18nOption ¶
type I18nOption = middlewares.I18nOption
I18nOption configures the I18n middleware.
func WithI18nDefaultFormat ¶
func WithI18nDefaultFormat(f *i18n.LocaleFormat) I18nOption
WithI18nDefaultFormat sets the fallback locale format.
func WithI18nExtractor ¶
func WithI18nExtractor(ext Extractor) I18nOption
WithI18nExtractor sets a custom language extractor chain.
func WithI18nFormatMap ¶
func WithI18nFormatMap(m map[string]*i18n.LocaleFormat) I18nOption
WithI18nFormatMap sets the language-to-format mapping.
type JWTClaimsKey ¶
type JWTClaimsKey = internal.JWTClaimsKey
JWTClaimsKey is the context key used to store parsed JWT claims.
type JWTOption ¶
type JWTOption = middlewares.JWTOption
JWTOption configures the JWT middleware.
func WithJWTExtractor ¶
WithJWTExtractor sets a custom token extractor for the JWT middleware.
type LanguageKey ¶
type LanguageKey = internal.LanguageKey
LanguageKey is the context key used to store the resolved language string.
type Middleware ¶
type Middleware = internal.Middleware
Middleware wraps a HandlerFunc to add cross-cutting concerns.
type Option ¶
Option configures the application.
func WithCookieConfig ¶
WithCookieConfig configures the cookie manager.
func WithCustomLogger ¶
WithCustomLogger sets a fully custom logger. Use this when you need complete control over logging configuration.
func WithErrorHandler ¶
func WithErrorHandler(h ErrorHandler) Option
WithErrorHandler sets a custom error handler for handler errors. Called when a handler returns a non-nil error.
func WithHandlers ¶
WithHandlers registers handlers that declare routes. Each handler's Routes method is called during setup.
func WithHealthChecks ¶
func WithHealthChecks(checks ...HealthCheckOption) Option
WithHealthChecks enables health check endpoints. Liveness: /_live — always returns OK if process is running. Readiness: /_ready — runs all configured checks.
func WithJobEnqueuer ¶
func WithJobEnqueuer(pool *pgxpool.Pool, opts ...job.EnqueuerOption) Option
WithJobEnqueuer enables job enqueueing without worker processing. Use this for web servers that dispatch work to separate worker processes. Workers must be running elsewhere to process the enqueued jobs.
func WithJobWorker ¶
WithJobWorker enables job processing without enqueueing capability. Use this for dedicated background worker processes that don't need to dispatch additional jobs. Workers are started automatically when the app runs and stopped gracefully during shutdown.
func WithJobs ¶
WithJobs enables both job enqueueing and worker processing using River. A pgxpool.Pool is required for the job queue. Workers are started automatically when the app runs and stopped gracefully during shutdown.
func WithLogger ¶
func WithLogger(component string, extractors ...logger.ContextExtractor) Option
WithLogger creates a logger with a component name and optional extractors. The component name is added to every log entry for easy filtering. Extractors pull values from context (e.g., request_id, user_id).
func WithMethodNotAllowedHandler ¶
func WithMethodNotAllowedHandler(h HandlerFunc) Option
WithMethodNotAllowedHandler sets a custom 405 handler.
func WithMiddleware ¶
func WithMiddleware(mw ...Middleware) Option
WithMiddleware adds global middleware to the application. Middleware is applied in the order provided.
func WithNotFoundHandler ¶
func WithNotFoundHandler(h HandlerFunc) Option
WithNotFoundHandler sets a custom 404 handler.
func WithRoles ¶
func WithRoles(permissions RolePermissions, extractor RoleExtractorFunc) Option
WithRoles configures role-based access control for the application. The permissions map defines which permissions each role grants. The extractor function determines the current user's role from the request context. Roles are extracted lazily (once per request) and cached.
func WithSSEKeepAlive ¶
WithSSEKeepAlive sets the interval for SSE keepalive comments. Defaults to 30 seconds if not set or if d <= 0.
func WithSession ¶
func WithSession(store SessionStore, opts ...SessionOption) Option
WithSession enables server-side session management. A SessionStore implementation must be provided (e.g., PostgresStore). Sessions are loaded lazily and saved automatically before the response is written.
Example:
app := forge.New(
forge.WithSession(postgresStore,
forge.WithSessionTTL(7 * 24 * time.Hour), // 7 days
forge.WithMaxSessionsPerUser(3), // Max 3 devices
forge.WithSessionFingerprint(
forge.FingerprintCookie, // Mode
forge.FingerprintWarn, // Strictness
),
),
)
Sessions auto-create on first access. No manual c.InitSession() required.
func WithStaticFiles ¶
WithStaticFiles mounts a static file handler at the given pattern. Directory listings are disabled. Files are served with default cache headers.
func WithStorage ¶
WithStorage configures file storage for the application. A storage.Storage implementation must be provided (e.g., S3Client). Enables c.Upload(), c.UploadFromURL(), c.Download(), c.DeleteFile(), and c.FileURL().
type PanicError ¶
type PanicError = middlewares.PanicError
PanicError represents a recovered panic.
func AsPanicError ¶
func AsPanicError(err error) (*PanicError, bool)
AsPanicError extracts the PanicError from an error if present.
type Permission ¶
type Permission = internal.Permission
Permission represents a named permission string.
type RateLimitOption ¶
type RateLimitOption = middlewares.RateLimitOption
RateLimitOption configures the RateLimit middleware.
type ResponseWriter ¶
type ResponseWriter = internal.ResponseWriter
ResponseWriter wraps http.ResponseWriter with hooks and HTMX support.
type RoleExtractorFunc ¶
type RoleExtractorFunc = internal.RoleExtractorFunc
RoleExtractorFunc extracts the current user's role from the request context.
type RolePermissions ¶
type RolePermissions = internal.RolePermissions
RolePermissions maps role names to their granted permissions.
type RunOption ¶
RunOption configures the server runtime.
func WithContext ¶
WithContext sets a custom base context for signal handling. Useful for testing or when integrating with existing context hierarchies. Defaults to context.Background() if not set.
func WithDomain ¶
WithDomain maps a host pattern to an App. Patterns: "api.example.com" (exact) or "*.example.com" (wildcard)
func WithFallback ¶
WithFallback sets the default App for requests that don't match any domain. If no domains are configured, the fallback becomes the main handler.
func WithRunLogger ¶
WithRunLogger sets the application logger for the runtime. If nil, logging is disabled.
func WithShutdownHook ¶
WithShutdownHook registers a cleanup function to run during shutdown. Hooks are called in the order they were registered. Each hook receives a context with the shutdown timeout.
func WithStartupHook ¶
WithStartupHook registers a function to run during server startup. Hooks are called in the order they were registered, after the port is bound but before serving requests. If any hook fails, the server stops and returns the error.
type SessionOption ¶
type SessionOption = internal.SessionOption
SessionOption configures the session manager.
type SessionStore ¶
SessionStore defines the interface for session persistence.
type TranslatorKey ¶
type TranslatorKey = internal.TranslatorKey
TranslatorKey is the context key used to store the i18n Translator.
type ValidationErrors ¶
type ValidationErrors = internal.ValidationErrors
ValidationErrors is a collection of validation errors.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package forgetest provides a fluent testing API for forge HTTP handlers.
|
Package forgetest provides a fluent testing API for forge HTTP handlers. |
|
Package internal provides the core types and implementation for the Forge framework.
|
Package internal provides the core types and implementation for the Forge framework. |
|
Package middlewares provides HTTP middleware for Forge applications.
|
Package middlewares provides HTTP middleware for Forge applications. |
|
pkg
|
|
|
binder
Package binder provides comprehensive HTTP request data binding utilities for Go web applications.
|
Package binder provides comprehensive HTTP request data binding utilities for Go web applications. |
|
cache
Package cache provides a generic Cache interface with in-memory and Redis implementations.
|
Package cache provides a generic Cache interface with in-memory and Redis implementations. |
|
clientip
Package clientip extracts real client IP addresses from HTTP requests.
|
Package clientip extracts real client IP addresses from HTTP requests. |
|
cookie
Package cookie provides HTTP cookie management with optional signing and encryption.
|
Package cookie provides HTTP cookie management with optional signing and encryption. |
|
db
Package db provides PostgreSQL database utilities optimized for SaaS applications.
|
Package db provides PostgreSQL database utilities optimized for SaaS applications. |
|
dnsverify
Package dnsverify provides DNS-based domain ownership verification.
|
Package dnsverify provides DNS-based domain ownership verification. |
|
fingerprint
Package fingerprint provides device fingerprinting from HTTP requests for session validation and security.
|
Package fingerprint provides device fingerprinting from HTTP requests for session validation and security. |
|
geolocation
Package geolocation provides IP geolocation lookups via MaxMind GeoIP2/GeoLite2 databases.
|
Package geolocation provides IP geolocation lookups via MaxMind GeoIP2/GeoLite2 databases. |
|
hostrouter
Package hostrouter provides host-based HTTP routing.
|
Package hostrouter provides host-based HTTP routing. |
|
htmx
Package htmx provides utilities for working with HTMX requests and responses.
|
Package htmx provides utilities for working with HTMX requests and responses. |
|
i18n
Package i18n provides internationalization support with immutable, thread-safe design and comprehensive locale handling for Go applications.
|
Package i18n provides internationalization support with immutable, thread-safe design and comprehensive locale handling for Go applications. |
|
id
Package id provides sortable ID generation utilities for use throughout the framework.
|
Package id provides sortable ID generation utilities for use throughout the framework. |
|
job
Package job provides background job processing using River (Postgres-native queue).
|
Package job provides background job processing using River (Postgres-native queue). |
|
jwt
Package jwt provides RFC 7519 compliant JSON Web Token implementation using HMAC-SHA256.
|
Package jwt provides RFC 7519 compliant JSON Web Token implementation using HMAC-SHA256. |
|
logger
Package logger provides structured logging with context extraction and Sentry integration.
|
Package logger provides structured logging with context extraction and Sentry integration. |
|
mailer
Package mailer provides a universal email sending interface with template rendering.
|
Package mailer provides a universal email sending interface with template rendering. |
|
mailer/smtp
Package smtp provides an SMTP adapter that implements mailer.Sender using only the Go standard library.
|
Package smtp provides an SMTP adapter that implements mailer.Sender using only the Go standard library. |
|
oauth
Package oauth provides OAuth2 authorization code flow implementations for common providers.
|
Package oauth provides OAuth2 authorization code flow implementations for common providers. |
|
qrcode
Package qrcode generates QR code images from string content.
|
Package qrcode generates QR code images from string content. |
|
randomname
Package randomname generates human-readable random names using cryptographically secure randomness.
|
Package randomname generates human-readable random names using cryptographically secure randomness. |
|
ratelimit
Package ratelimit provides a sliding window rate limiter with pluggable storage backends.
|
Package ratelimit provides a sliding window rate limiter with pluggable storage backends. |
|
redis
Package redis provides Redis client utilities optimized for SaaS applications.
|
Package redis provides Redis client utilities optimized for SaaS applications. |
|
sanitizer
Package sanitizer provides comprehensive input sanitization and data cleaning utilities for web applications.
|
Package sanitizer provides comprehensive input sanitization and data cleaning utilities for web applications. |
|
secrets
Package secrets provides AES-256-GCM encryption with compound key derivation for tenant-isolated data encryption in multi-tenant SaaS applications.
|
Package secrets provides AES-256-GCM encryption with compound key derivation for tenant-isolated data encryption in multi-tenant SaaS applications. |
|
slug
Package slug generates URL-safe slugs from arbitrary strings with Unicode normalization.
|
Package slug generates URL-safe slugs from arbitrary strings with Unicode normalization. |
|
storage
Package storage provides S3-compatible file storage operations.
|
Package storage provides S3-compatible file storage operations. |
|
token
Package token provides compact URL-safe signed tokens with truncated HMAC-SHA256.
|
Package token provides compact URL-safe signed tokens with truncated HMAC-SHA256. |
|
totp
Package totp provides RFC 6238 compliant Time-based One-Time Password (TOTP) authentication with AES-256-GCM secret encryption and backup recovery codes.
|
Package totp provides RFC 6238 compliant Time-based One-Time Password (TOTP) authentication with AES-256-GCM secret encryption and backup recovery codes. |
|
totp/cmd
command
|
|
|
useragent
Package useragent provides User-Agent string parsing to extract browser, operating system, and device information for web analytics, content optimization, and request handling.
|
Package useragent provides User-Agent string parsing to extract browser, operating system, and device information for web analytics, content optimization, and request handling. |
|
validator
Package validator provides a rule-based data validation system with both programmatic and struct tag-based validation capabilities.
|
Package validator provides a rule-based data validation system with both programmatic and struct tag-based validation capabilities. |
|
webhook
Package webhook provides reliable HTTP webhook delivery with automatic retries and circuit breaking.
|
Package webhook provides reliable HTTP webhook delivery with automatic retries and circuit breaking. |