Documentation
¶
Overview ¶
Package torge is a batteries-included backend framework for Go that stays close to the standard library.
app := torge.New()
app.GET("/", func(c *torge.Context) error {
return c.JSON(200, map[string]string{"message": "hello"})
})
log.Fatal(app.Listen(":8080"))
Request pipeline ¶
Every request flows through a fixed, documented sequence of stages:
request ID -> tracing -> access log -> error boundary -> recovery -> security -> health endpoints -> global middleware (App.Use) -> routing -> group middleware -> route middleware -> handler
Built-in stages can be configured or disabled with Options; App.Pipeline lists the stages actually installed. Errors returned by handlers propagate outward; the error boundary renders them once, and the stages outside it (logging, tracing) observe both the rendered status and the original error.
Lifecycle ¶
An App moves through Building -> Starting -> Running -> Stopping -> Stopped. Registration (routes, middleware, providers, hooks) happens while Building. Start validates everything and reports all problems at once as Diagnostics, builds dependencies, runs start hooks in registration order and then marks the app ready. Shutdown stops accepting requests, waits for in-flight requests, then runs stop hooks in reverse order.
Index ¶
- Constants
- Variables
- func DefaultErrorHandler(c *Context, err error)
- func Delete[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
- func Dep[T any](c *Context) (T, error)
- func Get[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
- func Handle[I, O any](r Router, method, path string, h TypedHandler[I, O], opts ...RouteOption)
- func ListenAddr(addr string) (string, error)
- func MustDep[T any](c *Context) T
- func MustResolve[T any](a *App) T
- func Patch[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
- func Post[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
- func ProblemErrorHandler(c *Context, err error)
- func Put[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
- func ReplaceValue[T any](a *App, v T)
- func Resolve[T any](a *App) (T, error)
- func ServiceAs[T any](a *App, name string) (T, error)
- func StatusOf(err error) int
- func SupplyAs[T any](a *App, v T)
- func UserAs[T Principal](c *Context) (T, bool)
- type AccessLogConfig
- type App
- func (a *App) AddHook(h Hook)
- func (a *App) AddSecurityScheme(name string, s *openapi.SecurityScheme)
- func (a *App) AddTag(tag openapi.Tag)
- func (a *App) Cache(store cache.Store)
- func (a *App) CheckHealth(ctx context.Context) HealthReport
- func (a *App) Config(cfg any)
- func (a *App) Database(db Database, opts ...DatabaseOption)
- func (a *App) Done() <-chan struct{}
- func (a *App) Env() Env
- func (a *App) HealthCheck(name string, check HealthCheck, opts ...HealthOption)
- func (a *App) Invoke(fn any)
- func (a *App) Job(name string, h jobs.Handler, opts ...jobs.JobOption)
- func (a *App) Jobs(m *jobs.Manager)
- func (a *App) Listen(addr string) error
- func (a *App) ListenTLS(addr, certFile, keyFile string) error
- func (a *App) Logger() *slog.Logger
- func (a *App) Manage(name string, l Lifecycle)
- func (a *App) Modules() []string
- func (a *App) NewContext(w http.ResponseWriter, r *http.Request) *Context
- func (a *App) OnStart(name string, fn func(context.Context) error)
- func (a *App) OnStop(name string, fn func(context.Context) error)
- func (a *App) OpenAPI(cfg OpenAPIConfig)
- func (a *App) OpenAPIDocument() (*openapi.Document, error)
- func (a *App) Options() Options
- func (a *App) Pipeline() []string
- func (a *App) PrintRoutes(w io.Writer) error
- func (a *App) Provide(ctor any, opts ...ProvideOption)
- func (a *App) Register(mods ...Module)
- func (a *App) Replace(ctor any, opts ...ProvideOption)
- func (a *App) Routes() []RouteInfo
- func (a *App) Serve(ln net.Listener) error
- func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (a *App) Server() *http.Server
- func (a *App) Service(name string, svc any)
- func (a *App) Services() []string
- func (a *App) SetLogger(l *slog.Logger)
- func (a *App) Shutdown(ctx context.Context) error
- func (a *App) Start(ctx context.Context) error
- func (a *App) State() State
- func (a *App) Supply(values ...any)
- func (a *App) Transaction(ctx context.Context, fn func(ctx context.Context) error) error
- func (a *App) URL(name string, params ...string) (string, error)
- func (a *App) Validate() error
- type CheckResult
- type Context
- func (c *Context) Accepts(types ...string) string
- func (c *Context) AddVary(value string)
- func (c *Context) Attachment(path, filename string) error
- func (c *Context) Bind(dst any) error
- func (c *Context) BindFormValues(dst any, values url.Values) error
- func (c *Context) BindJSON(dst any) error
- func (c *Context) Body() io.ReadCloser
- func (c *Context) Bytes(status int, contentType string, b []byte) error
- func (c *Context) ClearCookie(name string)
- func (c *Context) Context() context.Context
- func (c *Context) Cookie(name string) (*http.Cookie, error)
- func (c *Context) Env() Env
- func (c *Context) File(path string) error
- func (c *Context) FileFS(fsys fs.FS, name string) error
- func (c *Context) Flush() error
- func (c *Context) Format(offers ...Offer) error
- func (c *Context) Get(key any) (any, bool)
- func (c *Context) GetHeader(name string) string
- func (c *Context) HTML(status int, html string) error
- func (c *Context) HandleError(err error)
- func (c *Context) Header(name, value string)
- func (c *Context) Hostname() string
- func (c *Context) Is(types ...string) bool
- func (c *Context) IsFromTrustedProxy() bool
- func (c *Context) JSON(status int, v any) error
- func (c *Context) Links(links map[string]string)
- func (c *Context) Location(url string)
- func (c *Context) Logger() *slog.Logger
- func (c *Context) Method() string
- func (c *Context) NoContent(code int) error
- func (c *Context) OnDone(fn func())
- func (c *Context) Param(name string) string
- func (c *Context) Params() []Param
- func (c *Context) Path() string
- func (c *Context) Query(name string) string
- func (c *Context) QueryDefault(name, def string) string
- func (c *Context) QueryInt(name string, def int) (int, error)
- func (c *Context) QueryValues() url.Values
- func (c *Context) ReadBody() ([]byte, error)
- func (c *Context) RealIP() string
- func (c *Context) Redirect(code int, url string) error
- func (c *Context) Request() *http.Request
- func (c *Context) RequestID() string
- func (c *Context) Response() *ResponseWriter
- func (c *Context) RouteName() string
- func (c *Context) RoutePattern() string
- func (c *Context) SSE() (*SSE, error)
- func (c *Context) Scheme() string
- func (c *Context) Secure() bool
- func (c *Context) Send(status int, v any) error
- func (c *Context) Set(key, value any)
- func (c *Context) SetContext(ctx context.Context)
- func (c *Context) SetCookie(cookie *http.Cookie)
- func (c *Context) SetPageLinks(path string, params PageParams, total int)
- func (c *Context) SetRequest(r *http.Request)
- func (c *Context) SetResponseWriter(w http.ResponseWriter) (restore func())
- func (c *Context) SetUser(p Principal)
- func (c *Context) Status(code int) error
- func (c *Context) StatusCode() int
- func (c *Context) Stream(status int, contentType string, fn func(w io.Writer) error) error
- func (c *Context) String(status int, s string) error
- func (c *Context) Type(t string)
- func (c *Context) User() Principal
- func (c *Context) Validate(v any) error
- func (c *Context) XHR() bool
- type CursorPage
- type CursorParams
- type Database
- type DatabaseOption
- type Diagnostic
- type Diagnostics
- type Empty
- type Env
- type Error
- func AsError(err error) *Error
- func BadRequest(code, message string) *Error
- func Conflict(code, message string) *Error
- func Forbidden(code, message string) *Error
- func Internal(code, message string) *Error
- func NewError(status int, code, message string) *Error
- func NotAcceptable(code, message string) *Error
- func NotFound(code, message string) *Error
- func ServiceUnavailable(code, message string) *Error
- func TooManyRequests(code, message string) *Error
- func Unauthorized(code, message string) *Error
- func UnprocessableEntity(code, message string) *Error
- func (e *Error) Error() string
- func (e *Error) Is(target error) bool
- func (e *Error) IsServerError() bool
- func (e *Error) Unwrap() error
- func (e *Error) WithDetails(details any) *Error
- func (e *Error) WithMessage(msg string) *Error
- func (e *Error) WithMeta(key string, value any) *Error
- func (e *Error) Wrap(err error) *Error
- type ErrorBody
- type ErrorDebug
- type ErrorHandler
- type ErrorPayload
- type Group
- func (g *Group) Any(path string, h Handler, opts ...RouteOption)
- func (g *Group) DELETE(path string, h Handler, opts ...RouteOption)
- func (g *Group) GET(path string, h Handler, opts ...RouteOption)
- func (g *Group) Group(prefix string, opts ...RouteOption) *Group
- func (g *Group) HEAD(path string, h Handler, opts ...RouteOption)
- func (g *Group) Handle(method, path string, h Handler, opts ...RouteOption)
- func (g *Group) Mount(prefix string, h http.Handler, opts ...RouteOption)
- func (g *Group) OPTIONS(path string, h Handler, opts ...RouteOption)
- func (g *Group) PATCH(path string, h Handler, opts ...RouteOption)
- func (g *Group) POST(path string, h Handler, opts ...RouteOption)
- func (g *Group) PUT(path string, h Handler, opts ...RouteOption)
- func (g *Group) Prefix() string
- func (g *Group) Use(mws ...Middleware)
- func (g *Group) Version(version string, opts ...RouteOption) *Group
- type Handler
- type HealthCheck
- type HealthChecker
- type HealthConfig
- type HealthOption
- type HealthReport
- type Hook
- type JSONSerializer
- type Lifecycle
- type Middleware
- type Module
- type ModuleFunc
- type NamedModule
- type Offer
- type OpenAPIConfig
- type Option
- func WithAccessLog(cfg *AccessLogConfig) Option
- func WithBodyLimit(n int64) Option
- func WithEnv(env Env) Option
- func WithErrorHandler(h ErrorHandler) Option
- func WithExposeErrors(expose bool) Option
- func WithHealth(cfg *HealthConfig) Option
- func WithLogger(l *slog.Logger) Option
- func WithRecovery(cfg *RecoveryConfig) Option
- func WithRedirectTrailingSlash(enabled bool) Option
- func WithRequestID(cfg *RequestIDConfig) Option
- func WithSecurity(cfg *SecurityConfig) Option
- func WithSerializer(s Serializer) Option
- func WithServer(cfg ServerConfig) Option
- func WithTracing(m Middleware) Option
- func WithTrustedProxies(proxies ...string) Option
- func WithValidator(v Validator) Option
- func WithoutDefaults() Option
- type Options
- type Page
- type PageParams
- type Param
- type Principal
- type ProblemBody
- type ProvideOption
- type RecoveryConfig
- type RequestIDConfig
- type ResponseWriter
- func (w *ResponseWriter) Before(fn func()) bool
- func (w *ResponseWriter) Flush()
- func (w *ResponseWriter) FlushError() error
- func (w *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error)
- func (w *ResponseWriter) ReadFrom(r io.Reader) (int64, error)
- func (w *ResponseWriter) Size() int64
- func (w *ResponseWriter) Status() int
- func (w *ResponseWriter) Unwrap() http.ResponseWriter
- func (w *ResponseWriter) Write(b []byte) (int, error)
- func (w *ResponseWriter) WriteHeader(code int)
- func (w *ResponseWriter) WriteString(s string) (int, error)
- func (w *ResponseWriter) Written() bool
- type Result
- type RouteInfo
- type RouteOption
- func Body[T any]() RouteOption
- func BodyLimit(bytes int64) RouteOption
- func Deprecated() RouteOption
- func Description(s string) RouteOption
- func Hidden() RouteOption
- func Name(name string) RouteOption
- func OperationID(id string) RouteOption
- func Public() RouteOption
- func RequestContentType(contentType string) RouteOption
- func RequestExample(example any) RouteOption
- func Responds(status int, description string) RouteOption
- func ResponseExample(status int, example any) RouteOption
- func Returns[T any](status int, description string) RouteOption
- func Scopes(scheme string, scopes ...string) RouteOption
- func Security(schemes ...string) RouteOption
- func Status(code int) RouteOption
- func Summary(s string) RouteOption
- func Sunset(date string) RouteOption
- func Tags(tags ...string) RouteOption
- type Router
- type SSE
- type SSEEvent
- type Scope
- type Search
- type SecurityConfig
- type Serializer
- type ServerConfig
- type Sort
- type State
- type Strict
- type Transactor
- type TypedHandler
- type Validator
Constants ¶
const ( DiagDuplicateRoute = "DUPLICATE_ROUTE" DiagInvalidRoute = "INVALID_ROUTE" DiagDuplicateRouteName = "DUPLICATE_ROUTE_NAME" DiagLateRegistration = "REGISTRATION_AFTER_START" DiagInvalidState = "INVALID_LIFECYCLE_STATE" DiagMissingDependency = "MISSING_DEPENDENCY" DiagDuplicateDependency = "DUPLICATE_DEPENDENCY" DiagDependencyCycle = "DEPENDENCY_CYCLE" DiagInvalidScope = "INVALID_SCOPE" DiagInvalidProvider = "INVALID_PROVIDER" DiagDuplicateService = "DUPLICATE_SERVICE" DiagDuplicateModule = "DUPLICATE_MODULE" DiagModuleFailed = "MODULE_REGISTRATION_FAILED" DiagInvalidConfig = "INVALID_CONFIGURATION" DiagUnsafeProduction = "UNSAFE_PRODUCTION_CONFIGURATION" DiagDatabaseUnreachable = "DATABASE_UNREACHABLE" DiagStartFailed = "START_HOOK_FAILED" DiagInvalidHandler = "INVALID_HANDLER" DiagDuplicateHealthCheck = "DUPLICATE_HEALTH_CHECK" DiagLocalState = "PROCESS_LOCAL_STATE" DiagInvokeFailed = "INVOKE_FAILED" )
Diagnostic codes.
const ( CodeBadRequest = "BAD_REQUEST" CodeForbidden = "FORBIDDEN" CodeNotFound = "NOT_FOUND" CodeMethodNotAllowed = "METHOD_NOT_ALLOWED" CodeNotAcceptable = "NOT_ACCEPTABLE" CodeConflict = "CONFLICT" CodePayloadTooLarge = "PAYLOAD_TOO_LARGE" CodeUnsupportedMedia = "UNSUPPORTED_MEDIA_TYPE" CodeValidation = "VALIDATION_FAILED" CodeInvalidJSON = "INVALID_JSON" CodeTooManyRequests = "TOO_MANY_REQUESTS" CodeInternal = "INTERNAL_ERROR" CodeTimeout = "TIMEOUT" CodeRequestCanceled = "REQUEST_CANCELED" CodeRouteNotFound = "ROUTE_NOT_FOUND" CodeInvalidHost = "INVALID_HOST" CodeNotImplemented = "NOT_IMPLEMENTED" CodeUnprocessableContent = "UNPROCESSABLE_CONTENT" )
Error codes used by the framework.
const ( HealthUp = "up" HealthDown = "down" HealthStarting = "starting" HealthStopping = "stopping" )
Health statuses.
const ( Development = config.Development Test = config.Test Production = config.Production )
Deployment environments.
const ( // DefaultPageSize is used when the client sends no page size. DefaultPageSize = 20 // MaxPageSize caps the page size a client may request. MaxPageSize = 100 )
Pagination bounds shared by PageParams and CursorParams. The validate tags below mirror these values because struct tags cannot reference constants.
const DefaultBodyLimit = 4 << 20
DefaultBodyLimit is the default maximum request body size (4 MiB).
const DefaultPort = "8080"
DefaultPort is used by Listen("") when the PORT variable is unset.
const StatusClientClosedRequest = 499
StatusClientClosedRequest is the non-standard status used when the client disconnected before the response was written.
Variables ¶
var ErrInvalidSSEField = errors.New("torge: SSE id and event must not contain line breaks")
ErrInvalidSSEField is returned when an event's ID or type contains a line break.
Functions ¶
func DefaultErrorHandler ¶
DefaultErrorHandler writes the standard JSON error envelope.
func Delete ¶
func Delete[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
Delete registers a typed DELETE handler.
func Dep ¶
Dep returns the dependency of type T for the current request: a singleton, or a request-scoped value constructed on first use and cached for the rest of the request. Prefer constructor injection into handler types; Dep is for request-scoped values and small handlers.
func Get ¶
func Get[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
Get registers a typed GET handler.
func Handle ¶
func Handle[I, O any](r Router, method, path string, h TypedHandler[I, O], opts ...RouteOption)
Handle registers a typed handler for method and path on r.
func ListenAddr ¶
ListenAddr resolves an address the way Listen does: addr itself when non-empty, otherwise ":$PORT", otherwise ":8080".
func MustDep ¶
MustDep is like Dep but panics on error (the panic is recovered and rendered as a 500 by the recovery stage).
func MustResolve ¶
MustResolve is like Resolve but panics on error.
func Patch ¶
func Patch[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
Patch registers a typed PATCH handler.
func Post ¶
func Post[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
Post registers a typed POST handler.
func ProblemErrorHandler ¶ added in v0.3.0
ProblemErrorHandler renders errors as RFC 9457 problem details. Install it with WithErrorHandler; the default envelope is unchanged:
app := torge.New(torge.WithErrorHandler(torge.ProblemErrorHandler))
func Put ¶
func Put[I, O any](r Router, path string, h TypedHandler[I, O], opts ...RouteOption)
Put registers a typed PUT handler.
func ReplaceValue ¶
ReplaceValue registers v under type T, replacing any existing provider. Intended for tests.
func Resolve ¶
Resolve returns the singleton of type T. It is available once the application has started (including inside Invoke functions).
Types ¶
type AccessLogConfig ¶
type AccessLogConfig struct {
// SkipPaths are exact paths that are not logged. When nil, the health
// endpoints are skipped.
SkipPaths []string
// Skip decides per request whether to skip logging.
Skip func(c *Context) bool
// Attrs adds custom attributes.
Attrs func(c *Context) []slog.Attr
}
AccessLogConfig configures request logging.
type App ¶
type App struct {
// contains filtered or unexported fields
}
App is a Torge application. Create one with New.
Registration methods are safe to call from multiple goroutines but are meant to run during setup; after Start, the route table and pipeline are immutable and requests are served without locks.
func New ¶
New creates an application with production-safe defaults: request IDs, structured access logs, panic recovery, security headers, body limits, server timeouts and health endpoints.
func (*App) AddHook ¶
AddHook registers lifecycle callbacks. Start hooks run in registration order; stop hooks run in reverse order of successful starts.
func (*App) AddSecurityScheme ¶
func (a *App) AddSecurityScheme(name string, s *openapi.SecurityScheme)
AddSecurityScheme registers an OpenAPI security scheme, for example from a module or an authentication extension.
func (*App) Cache ¶
Cache registers the application cache. It is supplied to the container as cache.Store. If the store implements Ping(ctx) error a readiness check is added, and if it implements io.Closer it is closed at shutdown.
In production, a process-local store (cache.Memory) is reported as a warning: each instance would see a different cache.
func (*App) CheckHealth ¶
func (a *App) CheckHealth(ctx context.Context) HealthReport
CheckHealth runs the readiness checks and returns a report, for programmatic use.
func (*App) Config ¶
Config registers a loaded configuration value (typically a pointer to a struct filled by config.Load). It is validated with the application's validator and, if it implements Validate() error, by that method; failures stop startup. The value is supplied to the container so modules and constructors can depend on it.
func (*App) Database ¶
func (a *App) Database(db Database, opts ...DatabaseOption)
Database registers a database. The application takes ownership of it:
- startup fails with a DATABASE_UNREACHABLE diagnostic if it cannot be pinged, so traffic is never accepted without a database;
- a readiness health check is added;
- it is closed at shutdown, after the HTTP server and jobs have stopped;
- it is supplied to the container under its concrete type.
The first registered database is the primary one used by App.Transaction.
func (*App) Done ¶
func (a *App) Done() <-chan struct{}
Done is closed once the application has fully stopped.
func (*App) HealthCheck ¶
func (a *App) HealthCheck(name string, check HealthCheck, opts ...HealthOption)
HealthCheck registers a named check. Checks are readiness checks unless registered with Liveness().
app.HealthCheck("database", db.Ping)
func (*App) Invoke ¶
Invoke registers a function that runs during Start, after all singletons are constructed and before the route table is frozen. Its parameters are resolved from the container; it may return an error. Modules use Invoke to register routes that need constructed services:
app.Invoke(func(users *UserService) {
app.GET("/users/:id", users.Get)
})
func (*App) Job ¶
Job registers a job handler. Without a manager set by Jobs, an in-memory manager is created (and reported as process-local state in production).
func (*App) Jobs ¶
Jobs sets the background job manager. Its workers start after all other components and stop right after the HTTP server, before dependencies are closed. It is supplied to the container as *jobs.Manager.
func (*App) Listen ¶
Listen starts the application and serves HTTP on addr until SIGINT/SIGTERM or Shutdown, then shuts down gracefully. It returns nil after a clean shutdown.
An empty addr listens on ":$PORT", the convention of Render, Heroku, Railway, Cloud Run and most other platforms, or ":8080" when PORT is unset:
app.Listen("") // like app.listen(process.env.PORT || 8080) in Express
func (*App) Logger ¶
Logger returns the application logger. Records logged with a request context carry request_id and trace_id attributes.
func (*App) NewContext ¶
NewContext creates a Context for w and r outside the normal request pipeline. It is intended for tests and adapters.
func (*App) OpenAPI ¶
func (a *App) OpenAPI(cfg OpenAPIConfig)
OpenAPI enables the OpenAPI document and documentation UI. The document is generated at startup from route definitions: typed handlers contribute parameter, body and response schemas (including validation constraints), and route options contribute summaries, tags and security.
func (*App) OpenAPIDocument ¶
OpenAPIDocument returns the generated document. It is available after Start when OpenAPI is enabled.
func (*App) Pipeline ¶
Pipeline returns the names of the stages every request passes through, in order, including global middleware. Available after Start.
func (*App) PrintRoutes ¶
PrintRoutes writes the route table to w as an aligned table.
func (*App) Provide ¶
func (a *App) Provide(ctor any, opts ...ProvideOption)
Provide registers a constructor. The constructor is a function whose parameters are its dependencies and whose results are the provided value and, optionally, an error:
func NewUserService(db *sqldb.DB, log *slog.Logger) (*UserService, error)
Besides registered types, constructors may depend on context.Context (the start context, or the request context for request-scoped providers), *slog.Logger, torge.Env and, for request-scoped providers only, *torge.Context. To provide an interface, return the interface type.
func (*App) Register ¶
Register registers modules in order. Registering two modules with the same name is reported as a diagnostic.
func (*App) Replace ¶
func (a *App) Replace(ctor any, opts ...ProvideOption)
Replace registers a constructor that replaces any existing provider of the same type. It is intended for tests that swap real dependencies for fakes.
func (*App) Serve ¶
Serve starts the application if needed and serves on ln until a signal or Shutdown. Set TORGE_ROUTES=1 to print the route table and exit instead.
func (*App) ServeHTTP ¶
func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler, so an App can be used with any server, httptest, or mounted inside another router. The app must be started.
func (*App) Server ¶
Server returns a configured *http.Server for this app, for callers that manage serving themselves.
func (*App) Service ¶
Service registers a named external service client (a payment SDK, object storage, another API). If it implements Lifecycle it is started and stopped with the application; if it implements HealthChecker a readiness check named "service:<name>" is added. Retrieve it with ServiceAs.
func (*App) SetLogger ¶
SetLogger replaces the application logger. Any slog handler works; it is wrapped so that request correlation attributes are added automatically. A nil logger selects the environment's default.
func (*App) Shutdown ¶
Shutdown gracefully stops the application:
- readiness reports "stopping" (and the app waits DrainDelay);
- the server stops accepting connections and waits for in-flight requests;
- stop hooks run in reverse start order (job workers, services, caches, databases, telemetry flushers).
It is safe to call more than once; later calls wait for the first.
func (*App) Start ¶
Start validates the application, builds dependencies, runs invocations, freezes the route table and runs start hooks. It fails with Diagnostics describing every problem found. Start is called by Listen and Serve; call it directly when serving through your own http.Server or in tests.
func (*App) Supply ¶
Supply registers ready-made values, keyed by their dynamic types. Supplied values are not lifecycle-managed.
func (*App) Transaction ¶
Transaction runs fn in a transaction of the primary database. The transaction is committed if fn returns nil and rolled back otherwise (including on panic). The database must implement Transactor.
type CheckResult ¶
type CheckResult struct {
Status string `json:"status"`
DurationMS float64 `json:"duration_ms"`
Optional bool `json:"optional,omitempty"`
// Error is included only when ExposeErrors is enabled.
Error string `json:"error,omitempty"`
// contains filtered or unexported fields
}
CheckResult is the outcome of a single check.
type Context ¶
type Context struct {
// contains filtered or unexported fields
}
Context is the per-request context passed to handlers and middleware.
Lifetime ¶
A Context is created for exactly one request and is never pooled or reused. It is valid only until the handler chain returns. Do not retain it, and do not use it from goroutines that outlive the request; pass c.Context() and copies of the values you need instead. Like http.ResponseWriter, a Context is not safe for concurrent use.
Cancellation ¶
c.Context() is the request's context.Context. It is canceled when the client disconnects or the server shuts down, and carries any deadline set by middleware such as Timeout. Pass it to database and service calls.
func (*Context) Accepts ¶ added in v0.3.0
Accepts returns the best match for the request Accept header from types, or "" when nothing matches. Entries accept MIME types or shorthands ("html", "json"). With no Accept header the first type wins; with no types the result is "".
func (*Context) AddVary ¶ added in v0.3.0
AddVary appends value to the Vary response header without duplicating it, so caches key on the negotiated dimension. Must be called before the response is written.
func (*Context) Attachment ¶
Attachment serves a local file as a download named filename.
func (*Context) Bind ¶
Bind populates dst (a pointer to a struct) from the request and validates it:
- fields tagged `path`, `query`, `header` or `cookie` are bound from the corresponding request parameters (with optional `default` tags);
- the request body is decoded into a field named Body if present, otherwise into dst itself;
- `validate` tags and Validatable are then checked.
Parameters are bound after the body, so a body can never overwrite them. Failures are returned as *Error values (400, 413, 415 or 422) ready to be returned from the handler.
func (*Context) BindFormValues ¶ added in v0.3.0
BindFormValues binds values (form fields, for example the url.Values returned by upload.Stream alongside streamed files) into dst's query-tagged fields and validates the result with the application's validator. Path, header and cookie parameters are left at their zero values. Unknown values fail only when dst embeds Strict.
func (*Context) BindJSON ¶
BindJSON decodes the request body into dst and validates it. An empty body is rejected. When dst is a struct embedding Strict, unknown JSON fields are rejected.
func (*Context) Body ¶
func (c *Context) Body() io.ReadCloser
Body returns the request body. It is subject to the route's body limit.
func (*Context) ClearCookie ¶ added in v0.3.0
ClearCookie expires the named cookie. The path defaults to "/", matching the common case for cookies set without an explicit path.
func (*Context) Context ¶
Context returns the request's context.Context. It carries the request ID (see correlation.RequestID) and the authenticated principal (see UserFrom).
func (*Context) File ¶
File serves a file from the local filesystem, handling Range and conditional requests.
func (*Context) Format ¶ added in v0.3.0
Format runs the offer whose name best matches the request Accept header, selected per RFC 9110 (most specific range wins, then highest q-value, then offer order). The first offer is the default when the client sends no Accept header, so list the preferred representation first. A Vary: Accept header is set on every response Format writes. When nothing matches Format returns a 406 error, so it can be returned directly from a handler:
return c.Format(
torge.Offer{Name: "json", Handle: func(c *torge.Context) error {
return c.JSON(200, user)
}},
torge.Offer{Name: "html", Handle: func(c *torge.Context) error {
return c.HTML(200, "<h1>hi</h1>")
}},
)
func (*Context) HandleError ¶
HandleError renders err immediately with the application's error handler, unless the response was already written. Most code simply returns errors; middleware that must finalize the response itself can call this.
func (*Context) Hostname ¶ added in v0.3.0
Hostname returns the request host without the port, lowercased. A bare IPv6 host keeps no brackets: "[::1]" and "::1" both yield "::1".
func (*Context) Is ¶ added in v0.3.0
Is reports whether the request Content-Type matches any of types. Each entry is a MIME type ("application/json") or a shorthand ("json"), which also matches structured-syntax suffixes ("application/hal+json").
func (*Context) IsFromTrustedProxy ¶
IsFromTrustedProxy reports whether the connection comes from a configured trusted proxy (see WithTrustedProxies).
func (*Context) JSON ¶
JSON encodes v with the application's serializer (JSON by default) and writes it with the given status. Encoding happens before headers are sent, so an encoding failure results in a clean error response.
func (*Context) Links ¶ added in v0.3.0
Links sets an RFC 8288 Link header from relation names to URLs, e.g. {"next": "/users?page=3", "last": "/users?page=9"}. Keys are sorted so output is deterministic. See SetPageLinks for the paginated shorthand.
func (*Context) Location ¶ added in v0.3.0
Location sets the Location response header without changing the status. Pair it with Redirect or a 201 Created response.
func (*Context) Logger ¶
Logger returns the application logger bound to this request, so records carry request_id and trace_id even when logged without a context.
func (*Context) OnDone ¶
func (c *Context) OnDone(fn func())
OnDone registers fn to run after the handler chain has finished and the response was written. Hooks run in reverse registration order.
func (*Context) QueryDefault ¶
QueryDefault returns a query parameter or def if absent or empty.
func (*Context) QueryInt ¶
QueryInt parses a query parameter as an int, returning def when absent. A malformed value yields a 400 error.
func (*Context) QueryValues ¶
QueryValues returns the parsed query string. The result is cached and must not be modified.
func (*Context) RealIP ¶
RealIP returns the client IP address. X-Forwarded-For is honored only when the connection comes from a trusted proxy; the header is then walked from right to left and the first address that is not itself a trusted proxy is returned. Without trusted proxies, the peer address is returned, so clients cannot spoof their IP.
func (*Context) Redirect ¶
Redirect replies with a redirect to url. code must be a 3xx status. Never redirect to unvalidated user input.
func (*Context) Request ¶
Request returns the current *http.Request. Its context carries the request ID and the authenticated principal.
func (*Context) Response ¶
func (c *Context) Response() *ResponseWriter
Response returns the response writer.
func (*Context) RoutePattern ¶
RoutePattern returns the matched route pattern such as "/users/:id", or "" when no route matched.
func (*Context) SSE ¶
SSE starts a Server-Sent Events response. The write timeout is lifted for this request. Send returns an error once the client disconnects; select on Done to stop producing events.
sse, err := c.SSE()
if err != nil { return err }
for {
select {
case <-sse.Done():
return nil
case msg := <-updates:
if err := sse.SendJSON("update", msg); err != nil { return err }
}
}
func (*Context) Scheme ¶
Scheme returns "https" or "http". X-Forwarded-Proto is honored only from trusted proxies.
func (*Context) Secure ¶ added in v0.3.0
Secure reports whether the request used TLS (directly or, from a trusted proxy, via X-Forwarded-Proto).
func (*Context) Send ¶ added in v0.3.0
Send writes v with status, dispatching on its type: nil writes headers only, strings as text/plain, []byte as application/octet-stream, and anything else as JSON.
func (*Context) Set ¶
Set stores a request-scoped value for later middleware or the handler. Use an unexported key type to avoid collisions.
func (*Context) SetContext ¶
SetContext replaces the request's context. Middleware uses it to attach deadlines or values; ctx must derive from c.Context().
func (*Context) SetPageLinks ¶ added in v0.3.0
func (c *Context) SetPageLinks(path string, params PageParams, total int)
SetPageLinks sets an RFC 8288 Link header for an offset-paginated resource at path with first/prev/next/last relations. The current request's query parameters are preserved and only page/page_size are overridden, so following next keeps filters and search terms. Clients that understand links can follow pages without building URLs; others can ignore the header. Call it before writing the response body.
func (*Context) SetRequest ¶
SetRequest replaces the request, for middleware that needs to modify it.
func (*Context) SetResponseWriter ¶
func (c *Context) SetResponseWriter(w http.ResponseWriter) (restore func())
SetResponseWriter makes subsequent writes go through w, which should wrap the current Response(). It returns a function that restores the previous writer; call it before the middleware returns. Compression and response capture middleware use it.
func (*Context) SetUser ¶
SetUser records the authenticated principal. Authentication middleware calls it; the principal is also attached to c.Context() (see UserFrom).
func (*Context) StatusCode ¶
StatusCode returns the status written so far, or 0.
func (*Context) Stream ¶
Stream writes a streaming response. fn receives a writer that flushes to the client on every Write. The server write timeout is lifted for this request, and c.Context() is canceled when the client disconnects or the application begins shutting down; fn must return when it is. Writes fail once the context is canceled.
func (*Context) Type ¶ added in v0.3.0
Type sets the Content-Type response header from a MIME type or an extension/shorthand ("html", "json"). Unknown shorthands fall back to application/octet-stream; text types gain a UTF-8 charset.
type CursorPage ¶ added in v0.3.0
type CursorPage[T any] struct { Items []T `json:"items"` NextCursor string `json:"next_cursor,omitempty"` HasMore bool `json:"has_more"` }
CursorPage is a cursor-pagination response envelope. NextCursor is empty when there are no more items.
func NewCursorPage ¶ added in v0.3.0
func NewCursorPage[T any](items []T, nextCursor string) *CursorPage[T]
NewCursorPage builds an envelope. A nil slice is normalized to an empty array; HasMore is set exactly when nextCursor is non-empty.
type CursorParams ¶ added in v0.3.0
type CursorParams struct {
Cursor string `query:"cursor"`
Limit int `query:"limit" default:"20" validate:"min=1,max=100"`
}
CursorParams declares cursor-pagination query parameters. The cursor itself is opaque to the framework; applications encode whatever resume point they need (an ID, timestamp or offset) and decode it in the handler.
func (CursorParams) CursorLimit ¶ added in v0.3.0
func (p CursorParams) CursorLimit() int
CursorLimit returns the maximum number of items to return, clamped to the valid range so direct construction stays safe.
type Database ¶
Database is the lifecycle contract Torge needs from a database handle. It is deliberately minimal and ORM-agnostic; sqldb.DB adapts *sql.DB, and contrib modules adapt pgx, GORM, Ent or Bun.
type DatabaseOption ¶
type DatabaseOption func(*databaseOptions)
DatabaseOption configures a registered database.
func DatabaseName ¶
func DatabaseName(name string) DatabaseOption
DatabaseName names a database for health reports and hooks (default "database"). Register additional databases with distinct names.
func DatabasePingTimeout ¶
func DatabasePingTimeout(d time.Duration) DatabaseOption
DatabasePingTimeout bounds the startup connectivity check (default 10s).
func SkipStartupPing ¶
func SkipStartupPing() DatabaseOption
SkipStartupPing disables the startup connectivity check.
type Diagnostic ¶
type Diagnostic struct {
// Code identifies the kind of problem, for example "DUPLICATE_ROUTE".
Code string
// What happened.
What string
// Where it happened (usually file:line of the offending registration).
Where string
// Why it matters.
Why string
// Fix explains how to resolve it.
Fix string
// Warning marks diagnostics that are reported but do not stop startup.
Warning bool
}
Diagnostic is an actionable description of a setup or runtime problem. It explains what happened, where, why it matters, and how to fix it.
func (*Diagnostic) Error ¶
func (d *Diagnostic) Error() string
type Diagnostics ¶
type Diagnostics []*Diagnostic
Diagnostics is a list of problems. It implements error so that startup can report every problem at once.
func (Diagnostics) Error ¶
func (ds Diagnostics) Error() string
func (Diagnostics) Unwrap ¶
func (ds Diagnostics) Unwrap() []error
Unwrap exposes the individual diagnostics to errors.Is and errors.As.
type Empty ¶
type Empty struct{}
Empty is a convenience input or output type for operations without one.
type Error ¶
type Error struct {
// Status is the HTTP status code.
Status int
// Code is a stable, machine-readable error code such as "USER_NOT_FOUND".
Code string
// Message is a human-readable message that is safe to show to clients.
Message string
// Details is optional public, structured information (for example the
// list of invalid fields).
Details any
// Meta is internal diagnostic metadata. It is logged, never sent.
Meta map[string]any
// Err is the underlying cause. It is logged, never sent.
Err error
}
Error is a structured application error.
The public part of an Error (Status, Code, Message and Details) is written to clients. The internal part (Err and Meta) is only logged; it is included in responses only when the application runs with ExposeErrors enabled, which is refused in production.
Errors are immutable: the With* methods return modified copies, so package level sentinel errors can be shared safely:
var ErrUserNotFound = torge.NotFound("USER_NOT_FOUND", "User does not exist")
return ErrUserNotFound.Wrap(err)
errors.Is(err, ErrUserNotFound) matches any Error with the same Status and Code, including wrapped copies.
func AsError ¶
AsError converts any error into an *Error for rendering:
- an *Error anywhere in the chain is returned as is;
- validate.Errors become 422 VALIDATION_FAILED with field details;
- *http.MaxBytesError becomes 413;
- context.DeadlineExceeded becomes 504, context.Canceled 499;
- anything else becomes an opaque 500 that wraps the original error.
func Internal ¶
Internal returns a 500 error. Its message is still public, so keep it generic; put diagnostic information in the wrapped error.
func NotAcceptable ¶ added in v0.3.0
NotAcceptable returns a 406 error.
func ServiceUnavailable ¶
ServiceUnavailable returns a 503 error.
func TooManyRequests ¶
TooManyRequests returns a 429 error.
func Unauthorized ¶
Unauthorized returns a 401 error.
func UnprocessableEntity ¶
UnprocessableEntity returns a 422 error.
func (*Error) Error ¶
Error implements the error interface. The string contains internal details and is intended for logs.
func (*Error) IsServerError ¶
IsServerError reports whether the error represents a server-side failure.
func (*Error) WithDetails ¶
WithDetails returns a copy of e with public details.
func (*Error) WithMessage ¶
WithMessage returns a copy of e with a different public message.
type ErrorBody ¶
type ErrorBody struct {
Error ErrorPayload `json:"error"`
}
ErrorBody is the JSON envelope written for errors.
type ErrorDebug ¶
type ErrorDebug struct {
Error string `json:"error,omitempty"`
Meta map[string]any `json:"meta,omitempty"`
}
ErrorDebug carries internal error information in development.
type ErrorHandler ¶
ErrorHandler renders an error returned by the handler chain. It is called at most once per request, and only if the response has not been written yet.
type ErrorPayload ¶
type ErrorPayload struct {
Code string `json:"code"`
Message string `json:"message"`
RequestID string `json:"request_id,omitempty"`
Details any `json:"details,omitempty"`
// Debug is present only when ExposeErrors is enabled.
Debug *ErrorDebug `json:"debug,omitempty"`
}
ErrorPayload is the content of an error response.
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
Group is a set of routes sharing a path prefix, middleware and options. Groups nest. The App itself embeds the root group, whose middleware is the application's global middleware.
Group middleware applies to every route of the group and its subgroups, regardless of whether Use is called before or after the routes are registered; within a group, middleware runs in the order it was added.
func (*Group) Any ¶
func (g *Group) Any(path string, h Handler, opts ...RouteOption)
Any registers the handler for all standard methods.
func (*Group) DELETE ¶
func (g *Group) DELETE(path string, h Handler, opts ...RouteOption)
DELETE registers a DELETE route.
func (*Group) GET ¶
func (g *Group) GET(path string, h Handler, opts ...RouteOption)
GET registers a GET route. HEAD requests are served by GET routes unless a HEAD route is registered.
func (*Group) Group ¶
func (g *Group) Group(prefix string, opts ...RouteOption) *Group
Group creates a subgroup. Options (including middleware) apply to all routes of the subgroup.
func (*Group) HEAD ¶
func (g *Group) HEAD(path string, h Handler, opts ...RouteOption)
HEAD registers a HEAD route.
func (*Group) Handle ¶
func (g *Group) Handle(method, path string, h Handler, opts ...RouteOption)
Handle registers a handler for method and path. Any method token is accepted, including custom methods.
func (*Group) Mount ¶
func (g *Group) Mount(prefix string, h http.Handler, opts ...RouteOption)
Mount serves a standard http.Handler under prefix for all standard methods. The prefix is stripped from the request path before h sees it.
func (*Group) OPTIONS ¶
func (g *Group) OPTIONS(path string, h Handler, opts ...RouteOption)
OPTIONS registers an OPTIONS route. Without one, OPTIONS requests are answered automatically with an Allow header.
func (*Group) PATCH ¶
func (g *Group) PATCH(path string, h Handler, opts ...RouteOption)
PATCH registers a PATCH route.
func (*Group) POST ¶
func (g *Group) POST(path string, h Handler, opts ...RouteOption)
POST registers a POST route.
func (*Group) PUT ¶
func (g *Group) PUT(path string, h Handler, opts ...RouteOption)
PUT registers a PUT route.
func (*Group) Use ¶
func (g *Group) Use(mws ...Middleware)
Use appends middleware. On the App this is global middleware, which runs for every request before routing (including requests that match no route). On a Group it runs for the group's routes after routing.
func (*Group) Version ¶ added in v0.3.0
func (g *Group) Version(version string, opts ...RouteOption) *Group
Version creates a versioned API subgroup with prefix "/api/<version>" and an OpenAPI tag for the version, for example:
v1 := app.Version("v1")
v2 := app.Version("v2")
legacy := app.Version("v0", torge.Sunset("Mon, 01 Jun 2026 00:00:00 GMT"))
Pair it with middleware.APIVersion when clients negotiate versions with an Accept-Version header, or branch on media types with Context.Format. For a different prefix scheme, use Group directly.
type Handler ¶
Handler handles a request. Returning a non-nil error hands it to the error handler, which renders a response unless one was already written.
func Chain ¶
func Chain(h Handler, mws ...Middleware) Handler
Chain composes middleware so that mws[0] is the outermost.
func WrapFunc ¶
func WrapFunc(f http.HandlerFunc) Handler
WrapFunc adapts a standard http.HandlerFunc.
func WrapHandler ¶
WrapHandler adapts a standard http.Handler. Use it to mount existing net/http components without rewriting them.
type HealthCheck ¶
HealthCheck reports whether a dependency is healthy. It must honor ctx.
type HealthChecker ¶
HealthChecker is implemented by components that can check their own health. Services registered with App.Service that implement it get a readiness check automatically.
type HealthConfig ¶
type HealthConfig struct {
LivePath string
ReadyPath string
HealthPath string
// Timeout bounds each check (default 5s). Checks run concurrently, so a
// probe never takes longer than the slowest timeout.
Timeout time.Duration
}
HealthConfig configures the health endpoints. Empty paths use the defaults; set a path to "-" to disable that endpoint.
- LivePath (default /live) answers whether the process is alive. It runs only checks registered with Liveness(), so a slow dependency never causes a restart.
- ReadyPath (default /ready) answers whether the application should receive traffic: it is 503 while starting or stopping, and when a required check fails.
- HealthPath (default /health) returns a detailed report of every check.
Health endpoints run before global middleware, so authentication or rate limiting added with App.Use never blocks orchestrator probes, and they are excluded from access logs by default.
type HealthOption ¶
type HealthOption func(*healthCheck)
HealthOption configures a health check.
func CheckTimeout ¶
func CheckTimeout(d time.Duration) HealthOption
CheckTimeout overrides the timeout of one check.
func Liveness ¶
func Liveness() HealthOption
Liveness includes the check in the liveness endpoint. Use it only for failures that a restart fixes (for example a deadlocked worker).
func Optional ¶
func Optional() HealthOption
Optional reports the check without letting its failure make the application unready.
type HealthReport ¶
type HealthReport struct {
Status string `json:"status"`
Checks map[string]CheckResult `json:"checks,omitempty"`
}
HealthReport is the body of the health endpoints.
type Hook ¶
type Hook struct {
Name string
OnStart func(context.Context) error
OnStop func(context.Context) error
}
Hook is a named pair of lifecycle callbacks.
type JSONSerializer ¶
type JSONSerializer struct {
// DisallowUnknownFields rejects request bodies with unknown fields.
DisallowUnknownFields bool
}
JSONSerializer is the default Serializer, built on encoding/json.
func (JSONSerializer) ContentType ¶
func (JSONSerializer) ContentType() string
ContentType implements Serializer.
type Middleware ¶
Middleware wraps a Handler. Code before calling next runs on the way in, code after it runs on the way out; not calling next short-circuits the request.
func Timing(next torge.Handler) torge.Handler {
return func(c *torge.Context) error {
start := time.Now()
err := next(c)
c.Logger().Info("took", "duration", time.Since(start))
return err
}
}
A Middleware can be passed directly as a route or group option.
func Logger ¶
func Logger(cfgs ...AccessLogConfig) Middleware
Logger logs one structured record per request after it completes, with method, route, path, status, duration, size, client IP, user ID and error. request_id and trace_id are added from the request context. Server errors log at Error, client errors at Warn, everything else at Info.
func Recovery ¶
func Recovery(cfgs ...RecoveryConfig) Middleware
Recovery converts panics into 500 errors: the panic is recovered, logged with its stack trace and request metadata, and a controlled response is rendered, so one request can never crash the server. http.ErrAbortHandler is re-panicked to preserve its standard meaning.
func RequestID ¶
func RequestID(cfgs ...RequestIDConfig) Middleware
RequestID assigns every request an ID: a valid, trusted incoming ID is reused, otherwise one is generated. The ID is attached to the Context, to c.Context() (see correlation.RequestID), to logs, to error responses and to the response header. It is a no-op if an ID was already assigned.
func SecurityHeaders ¶
func SecurityHeaders(cfgs ...SecurityConfig) Middleware
SecurityHeaders sets security headers on every response and rejects requests for hosts outside AllowedHosts with 400.
func WrapMiddleware ¶
func WrapMiddleware(m func(http.Handler) http.Handler) Middleware
WrapMiddleware adapts standard func(http.Handler) http.Handler middleware. Request and response-writer changes made by the standard middleware are visible to the rest of the chain, and errors returned by the rest of the chain propagate back normally.
type Module ¶
Module groups the registrations of one area of an application: routes, middleware, providers, hooks, health checks, jobs and OpenAPI metadata. Modules do not impose an architecture; they are simply a named unit of registration.
type UserModule struct{}
func (UserModule) Register(app *torge.App) error {
app.Provide(NewUserStore)
app.Provide(NewUserService)
app.Invoke(func(svc *UserService) {
users := app.Group("/users", torge.Tags("users"))
torge.Get(users, "/:id", svc.Get)
})
return nil
}
Routes registered by a module (including inside its Invoke functions) are attributed to it in route introspection. Implement Name to control the module name; by default the type name is used.
type ModuleFunc ¶
ModuleFunc adapts a function to a Module.
func (ModuleFunc) Register ¶
func (f ModuleFunc) Register(app *App) error
Register implements Module.
type NamedModule ¶
NamedModule is a Module with an explicit name.
type Offer ¶ added in v0.3.0
Offer is one response representation Format can serve. Name accepts a MIME type or a shorthand ("html", "json").
type OpenAPIConfig ¶
type OpenAPIConfig struct {
Info openapi.Info
Servers []openapi.Server
Tags []openapi.Tag
// SecuritySchemes are the available authentication schemes, referenced
// by name from Security route options.
SecuritySchemes map[string]*openapi.SecurityScheme
// Security is the default requirement for all operations.
Security []openapi.SecurityRequirement
// SpecPath serves the JSON document (default /openapi.json, "-"
// disables).
SpecPath string
// DocsPath serves interactive documentation (default /docs, "-"
// disables).
DocsPath string
// UI selects the documentation renderer (default Swagger UI).
UI openapi.UI
// RouteOptions apply to the spec and docs routes, for example
// authentication middleware to keep documentation private.
RouteOptions []RouteOption
}
OpenAPIConfig enables and configures the generated OpenAPI document.
type Option ¶
type Option func(*Options)
Option configures an App.
func WithAccessLog ¶
func WithAccessLog(cfg *AccessLogConfig) Option
WithAccessLog configures request logging. Pass nil to disable.
func WithBodyLimit ¶
WithBodyLimit sets the default request body limit in bytes.
func WithErrorHandler ¶
func WithErrorHandler(h ErrorHandler) Option
WithErrorHandler replaces the error renderer.
func WithExposeErrors ¶
WithExposeErrors controls whether internal error details are included in responses. Enabling it in production makes Start fail.
func WithHealth ¶
func WithHealth(cfg *HealthConfig) Option
WithHealth configures health endpoints. Pass nil to disable.
func WithRecovery ¶
func WithRecovery(cfg *RecoveryConfig) Option
WithRecovery configures panic recovery. Pass nil to disable.
func WithRedirectTrailingSlash ¶
WithRedirectTrailingSlash toggles trailing-slash redirects.
func WithRequestID ¶
func WithRequestID(cfg *RequestIDConfig) Option
WithRequestID configures request IDs. Pass nil to disable.
func WithSecurity ¶
func WithSecurity(cfg *SecurityConfig) Option
WithSecurity configures security headers and host validation. Pass nil to disable.
func WithSerializer ¶
func WithSerializer(s Serializer) Option
WithSerializer replaces the body serializer.
func WithServer ¶
func WithServer(cfg ServerConfig) Option
WithServer sets server timeouts and limits.
func WithTracing ¶
func WithTracing(m Middleware) Option
WithTracing installs tracing middleware (for example from contrib/otel) in the pipeline slot right after request IDs, so every later stage is traced.
func WithTrustedProxies ¶
WithTrustedProxies sets the trusted reverse proxies (IPs or CIDRs).
func WithValidator ¶
WithValidator replaces the request validator.
func WithoutDefaults ¶
func WithoutDefaults() Option
WithoutDefaults disables every optional built-in stage (request IDs, access log, recovery, security headers, health endpoints). Server timeouts and body limits stay in place. Use it to compose the pipeline by hand.
type Options ¶
type Options struct {
// Env is the deployment environment. Defaults to config.CurrentEnv(),
// which is Production unless TORGE_ENV or APP_ENV says otherwise.
Env Env
// Logger is the application logger. Defaults to JSON on stdout in
// production and text in development.
Logger *slog.Logger
// Server configures timeouts and limits.
Server ServerConfig
// BodyLimit is the default maximum request body size. Negative disables.
BodyLimit int64
// ErrorHandler renders errors. Defaults to DefaultErrorHandler.
ErrorHandler ErrorHandler
// Validator validates bound requests. Defaults to validate.Default.
Validator Validator
// Serializer encodes and decodes bodies. Defaults to JSON.
Serializer Serializer
// ExposeErrors adds internal error details to responses. It defaults to
// true only in development and is refused in production.
ExposeErrors bool
// TrustedProxies lists CIDRs or IPs of reverse proxies whose forwarding
// headers (X-Forwarded-For, X-Forwarded-Proto, X-Request-ID) are trusted.
TrustedProxies []string
// RedirectTrailingSlash redirects /path/ to /path (and vice versa) when
// only the other form is registered. Default true.
RedirectTrailingSlash bool
// Built-in pipeline stages. A nil pointer disables the stage.
RequestID *RequestIDConfig
Tracing Middleware
AccessLog *AccessLogConfig
Recovery *RecoveryConfig
Security *SecurityConfig
Health *HealthConfig
// contains filtered or unexported fields
}
Options configures an App. Use the With* functions with New.
type Page ¶ added in v0.3.0
type Page[T any] struct { Items []T `json:"items"` Total int `json:"total"` Page int `json:"page"` PageSize int `json:"page_size"` Pages int `json:"pages"` }
Page is an offset-pagination response envelope. Total is the number of items across all pages; Pages is derived from Total and the page size.
func NewPage ¶ added in v0.3.0
func NewPage[T any](items []T, total int, params PageParams) *Page[T]
NewPage builds an envelope for items with total matching items across all pages. A nil slice is normalized to an empty array so clients always see an array. Non-positive totals yield zero pages.
type PageParams ¶ added in v0.3.0
type PageParams struct {
Page int `query:"page" default:"1" validate:"min=1,max=1000000"`
PageSize int `query:"page_size" default:"20" validate:"min=1,max=100"`
}
PageParams declares offset-pagination query parameters. Embed it in a handler input; Context.Bind applies defaults and validates bounds. Page is capped so adversarial values cannot push Offset past what a database accepts; Offset additionally saturates instead of overflowing.
func (PageParams) Limit ¶ added in v0.3.0
func (p PageParams) Limit() int
Limit returns the maximum number of items to return for the current page.
func (PageParams) Offset ¶ added in v0.3.0
func (p PageParams) Offset() int
Offset returns the number of items to skip for the current page. Values below the valid range are clamped, and huge pages saturate at maxInt instead of overflowing negative, so the result is always safe for OFFSET clauses.
type Principal ¶
type Principal interface {
// ID returns a stable identifier for the principal, for logs and
// per-user limits.
ID() string
}
Principal is an authenticated identity. Applications define their own principal types; auth.User is a ready-made implementation.
type ProblemBody ¶ added in v0.3.0
type ProblemBody struct {
Type string `json:"type"`
Title string `json:"title"`
Status int `json:"status"`
Detail string `json:"detail,omitempty"`
Instance string `json:"instance,omitempty"`
Code string `json:"code,omitempty"`
RequestID string `json:"request_id,omitempty"`
Details any `json:"details,omitempty"`
Debug *ErrorDebug `json:"debug,omitempty"`
}
ProblemBody is an RFC 9457 problem-details error document.
ProblemErrorHandler writes errors in this shape with Content-Type application/problem+json. Type stays "about:blank" per the RFC; the stable Torge code travels in the Code extension member so clients can match on it exactly like the default envelope.
func NewProblem ¶ added in v0.3.0
func NewProblem(e *Error, instance, requestID string) ProblemBody
NewProblem converts e to problem details for the request path. Title is the short, stable status summary; the occurrence-specific message goes in Detail.
type ProvideOption ¶
type ProvideOption func(*provider)
ProvideOption configures a provider.
func RequestScoped ¶
func RequestScoped() ProvideOption
RequestScoped makes a provider construct one value per request. Its constructor may depend on *torge.Context. Request-scoped values that implement io.Closer are closed when the request finishes.
type RecoveryConfig ¶
type RecoveryConfig struct {
// StackSize is the maximum stack trace size captured (default 8 KiB).
StackSize int
// DisableStack skips stack capture.
DisableStack bool
// OnPanic is called after the panic is logged, for example to report it
// to an error tracker.
OnPanic func(c *Context, recovered any, stack []byte)
}
RecoveryConfig configures panic recovery.
type RequestIDConfig ¶
type RequestIDConfig struct {
// Header carries the ID in requests and responses (default X-Request-ID).
Header string
// Generator creates new IDs (default: 26 random base32 characters).
Generator func() string
// TrustIncoming decides whether an incoming ID is accepted. By default,
// IDs are accepted only from trusted proxies, so clients cannot inject
// arbitrary values into logs.
TrustIncoming func(c *Context) bool
}
RequestIDConfig configures request ID handling.
type ResponseWriter ¶
type ResponseWriter struct {
http.ResponseWriter
// contains filtered or unexported fields
}
ResponseWriter wraps http.ResponseWriter to record the status code and the number of bytes written, and to run hooks just before headers are sent.
It supports http.Flusher, http.Hijacker, io.ReaderFrom and http.ResponseController (through Unwrap), so streaming, WebSockets and sendfile keep working.
func (*ResponseWriter) Before ¶
func (w *ResponseWriter) Before(fn func()) bool
Before registers fn to run immediately before headers are written. It is the last point at which headers and cookies can be changed. It reports false if headers were already written, in which case fn is not registered.
func (*ResponseWriter) FlushError ¶
func (w *ResponseWriter) FlushError() error
FlushError flushes buffered data to the client, committing headers first.
func (*ResponseWriter) Hijack ¶
func (w *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error)
Hijack implements http.Hijacker.
func (*ResponseWriter) ReadFrom ¶
func (w *ResponseWriter) ReadFrom(r io.Reader) (int64, error)
ReadFrom implements io.ReaderFrom, enabling sendfile when the underlying writer supports it.
func (*ResponseWriter) Size ¶
func (w *ResponseWriter) Size() int64
Size returns the number of body bytes written.
func (*ResponseWriter) Status ¶
func (w *ResponseWriter) Status() int
Status returns the status code sent, or 0 if headers were not written.
func (*ResponseWriter) Unwrap ¶
func (w *ResponseWriter) Unwrap() http.ResponseWriter
Unwrap returns the underlying writer for http.ResponseController.
func (*ResponseWriter) Write ¶
func (w *ResponseWriter) Write(b []byte) (int, error)
Write implements http.ResponseWriter.
func (*ResponseWriter) WriteHeader ¶
func (w *ResponseWriter) WriteHeader(code int)
WriteHeader implements http.ResponseWriter. Informational (1xx) statuses other than 101 are passed through without committing the response.
func (*ResponseWriter) WriteString ¶
func (w *ResponseWriter) WriteString(s string) (int, error)
WriteString implements io.StringWriter.
func (*ResponseWriter) Written ¶
func (w *ResponseWriter) Written() bool
Written reports whether headers have been sent.
type Result ¶ added in v0.3.0
Result is a uniform success envelope for single-resource responses. List responses use Page[T]; this covers the "one object plus metadata" case:
torge.Get(api, "/users/:id", func(c *torge.Context, in *GetUser) (*torge.Result[User], error) {
u, err := users.Find(c.Context(), in.ID)
if err != nil {
return nil, err
}
return torge.NewResult(u).WithMeta("cache", "hit"), nil
})
The shape renders as {"data": ..., "meta": {...}} with meta omitted when empty, so clients that only need the resource can ignore the envelope.
type RouteInfo ¶
type RouteInfo struct {
Method string `json:"method"`
Path string `json:"path"`
Name string `json:"name,omitempty"`
Handler string `json:"handler"`
Middleware []string `json:"middleware,omitempty"`
Module string `json:"module,omitempty"`
Location string `json:"location,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
}
RouteInfo describes a registered route for introspection and tooling.
type RouteOption ¶
type RouteOption interface {
// contains filtered or unexported methods
}
RouteOption configures a route or, when passed to Group, every route of the group. A Middleware is also a RouteOption.
func Body ¶
func Body[T any]() RouteOption
Body documents the request body type of an untyped handler.
func BodyLimit ¶
func BodyLimit(bytes int64) RouteOption
BodyLimit overrides the application's request body limit for a route. Use a negative value to disable the limit (for example for streaming uploads that enforce their own limits).
func Deprecated ¶
func Deprecated() RouteOption
Deprecated marks the operation as deprecated in OpenAPI.
func Name ¶
func Name(name string) RouteOption
Name names a route so that its URL can be built with App.URL.
func OperationID ¶
func OperationID(id string) RouteOption
OperationID sets the OpenAPI operation ID. By default the route name is used, or one is derived from the method and path.
func Public ¶
func Public() RouteOption
Public documents that the route requires no authentication, overriding security declared on a group or globally.
func RequestContentType ¶ added in v0.3.0
func RequestContentType(contentType string) RouteOption
RequestContentType overrides the documented request body media type (default application/json). Use it with Body for uploads:
app.POST("/avatar", uploadAvatar,
torge.Body[AvatarForm](),
torge.RequestContentType("multipart/form-data"))
File parts are declared with format:"binary" fields, for example a File string field tagged json:"file" format:"binary".
func RequestExample ¶ added in v0.3.0
func RequestExample(example any) RouteOption
RequestExample documents an example request body.
func Responds ¶
func Responds(status int, description string) RouteOption
Responds documents a response without a body, such as an error status.
func ResponseExample ¶ added in v0.3.0
func ResponseExample(status int, example any) RouteOption
ResponseExample documents an example response body for a status code. It pairs with Returns and Responds:
torge.Post(api, "/users", svc.Create,
torge.Status(201),
torge.Returns[User](201, "Created"),
torge.ResponseExample(201, User{ID: "1", Name: "Ada"}))
func Returns ¶
func Returns[T any](status int, description string) RouteOption
Returns documents a response body type for a status code.
func Scopes ¶ added in v0.3.0
func Scopes(scheme string, scopes ...string) RouteOption
Scopes documents the OAuth2 scopes required by the route, merging into security declared with Security on the route or its groups:
api := app.Group("/v1", torge.Security("oauth"))
api.GET("/me", getMe, torge.Scopes("oauth", "profile:read"))
func Security ¶
func Security(schemes ...string) RouteOption
Security declares the security schemes (by name, as registered with App.OpenAPI) that protect the route. Documentation only: enforcement is done by authentication middleware.
func Status ¶
func Status(code int) RouteOption
Status sets the success status code written by typed handlers and documented in OpenAPI. The default is 200 (204 when the output is nil).
func Sunset ¶ added in v0.3.0
func Sunset(date string) RouteOption
Sunset marks the route as deprecated and announces its retirement with RFC 8594 Deprecation/Sunset response headers. date is the retirement date in IMF-fixdate form ("Mon, 02 Jan 2006 15:04:05 GMT"); an empty date sends only the Deprecation header. The date is validated at registration, so a typo fails fast instead of shipping a bogus header. It applies to groups as well, so a whole version can sunset at once:
legacy := app.Version("v0", torge.Sunset("Mon, 01 Jun 2026 00:00:00 GMT"))
type Router ¶
type Router interface {
Handle(method, path string, h Handler, opts ...RouteOption)
}
Router is implemented by *App and *Group. Typed handler helpers such as Get and Post accept a Router.
type SSE ¶
type SSE struct {
// contains filtered or unexported fields
}
SSE is a Server-Sent Events stream. Obtain one with Context.SSE.
type SSEEvent ¶
type SSEEvent struct {
// ID sets the event ID, which clients send back as Last-Event-ID.
ID string
// Event is the event type; empty means "message".
Event string
// Data is the payload. Multi-line data is split into data lines.
Data string
// Retry tells the client how long to wait before reconnecting.
Retry time.Duration
}
SSEEvent is a Server-Sent Event.
type Search ¶ added in v0.3.0
type Search struct {
Q string `query:"q" validate:"max=100"`
}
Search declares a free-text query parameter. Embed it in a handler input alongside PageParams for searchable list endpoints.
type SecurityConfig ¶
type SecurityConfig struct {
// Headers adds or overrides response headers. A header mapped to "" is
// removed from the defaults. Defaults:
// X-Content-Type-Options: nosniff
// X-Frame-Options: DENY
// Referrer-Policy: strict-origin-when-cross-origin
Headers map[string]string
// ContentSecurityPolicy sets Content-Security-Policy when non-empty.
ContentSecurityPolicy string
// HSTSMaxAge enables Strict-Transport-Security on HTTPS requests.
HSTSMaxAge time.Duration
// HSTSIncludeSubdomains adds includeSubDomains to HSTS.
HSTSIncludeSubdomains bool
// AllowedHosts restricts accepted Host headers. Entries may be exact
// hosts or "*.example.com" wildcards. Empty allows any host.
AllowedHosts []string
}
SecurityConfig configures security headers and host validation.
type Serializer ¶
type Serializer interface {
ContentType() string
Encode(w io.Writer, v any) error
Decode(r io.Reader, v any) error
}
Serializer encodes response bodies and decodes request bodies.
type ServerConfig ¶
type ServerConfig struct {
// ReadHeaderTimeout bounds reading request headers (default 10s). It
// protects against slowloris attacks.
ReadHeaderTimeout time.Duration
// ReadTimeout bounds reading the entire request (default 30s).
ReadTimeout time.Duration
// WriteTimeout bounds writing the response (default 30s). Streaming
// helpers (Stream, SSE) lift it for their request.
WriteTimeout time.Duration
// IdleTimeout bounds keep-alive idle time (default 120s).
IdleTimeout time.Duration
// MaxHeaderBytes bounds request header size (default 1 MiB).
MaxHeaderBytes int
// StartTimeout bounds Start when called by Listen or Serve (default 60s).
StartTimeout time.Duration
// ShutdownTimeout bounds graceful shutdown (default 30s).
ShutdownTimeout time.Duration
// DrainDelay is how long the application keeps serving after readiness
// turns unhealthy at shutdown, so load balancers stop routing to it
// (default 0; typically 5-10s on Kubernetes).
DrainDelay time.Duration
}
ServerConfig configures the HTTP server. Zero fields use production-safe defaults.
type Sort ¶ added in v0.3.0
Sort is a single validated sort clause: Field names a sortable field and Desc selects descending order.
func ParseSort ¶ added in v0.3.0
ParseSort validates a comma-separated sort parameter against an allow-list of sortable fields. A leading "-" marks descending order, e.g. "-created_at,name". An empty parameter yields no clauses and no error. Unknown fields fail with a 400 *Error naming the allowed fields, ready to be returned from the handler.
type State ¶
type State int32
State is the lifecycle state of an App.
type Strict ¶ added in v0.3.0
Strict is an embedded marker enabling strict binding for an input type. Strict inputs reject JSON bodies with unknown fields and fail requests carrying undeclared query parameters with a 422 listing them:
type ListUsers struct {
torge.Strict
Q string `query:"q" validate:"max=100"`
}
It applies to Context.Bind, Context.BindJSON and typed handlers alike. Slice fields additionally accept `query:"tag,comma"` to split single values on commas, and time.Time fields accept `layout:"2006-01-02"` to parse non-RFC3339 timestamps.
type Transactor ¶
type Transactor interface {
Transaction(ctx context.Context, fn func(ctx context.Context) error) error
}
Transactor is implemented by databases that support context-carried transactions. Inside fn, the adapter's query helpers (for example sqldb.DB.Conn(ctx)) use the transaction automatically.
type TypedHandler ¶
TypedHandler is a handler with a typed input and output. The input is bound and validated before the handler runs (see Context.Bind); the output is encoded with the configured success status. Returning a nil output writes 204 No Content.
type GetUserInput struct {
ID string `path:"id" validate:"uuid"`
}
torge.Get(app, "/users/:id", func(c *torge.Context, in *GetUserInput) (*User, error) {
return users.Find(c.Context(), in.ID)
}, torge.Summary("Get a user"))
The same types drive the generated OpenAPI operation, so the contract is declared exactly once.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package auth provides authentication primitives: an Authenticator contract, middleware that runs one or more authenticators and exposes the principal through c.User(), and ready-made bearer token, API key and basic authenticators.
|
Package auth provides authentication primitives: an Authenticator contract, middleware that runs one or more authenticators and exposes the principal through c.User(), and ready-made bearer token, API key and basic authenticators. |
|
Package cache defines a small, pluggable key-value cache contract with an in-memory implementation.
|
Package cache defines a small, pluggable key-value cache contract with an in-memory implementation. |
|
cmd
|
|
|
torge
command
Command torge is the optional Torge CLI.
|
Command torge is the optional Torge CLI. |
|
Package config loads typed configuration from environment variables.
|
Package config loads typed configuration from environment variables. |
|
autoload
Package autoload loads .env files when imported, the Go equivalent of Node's require("dotenv/config"):
|
Package autoload loads .env files when imported, the Go equivalent of Node's require("dotenv/config"): |
|
contrib
|
|
|
jwt
module
|
|
|
mongo
module
|
|
|
otel
module
|
|
|
pgx
module
|
|
|
redis
module
|
|
|
Package correlation carries request and trace identifiers through a context.Context so that logs, outgoing HTTP calls and background jobs can be correlated with the request that caused them.
|
Package correlation carries request and trace identifiers through a context.Context so that logs, outgoing HTTP calls and background jobs can be correlated with the request that caused them. |
|
Package httpclient provides an HTTP client for calling external services with production defaults: timeouts, connection pooling, conservative retries with exponential backoff, request ID propagation, structured errors and optional logging.
|
Package httpclient provides an HTTP client for calling external services with production defaults: timeouts, connection pooling, conservative retries with exponential backoff, request ID propagation, structured errors and optional logging. |
|
Package idempotency makes non-idempotent operations (payments, orders, registrations) safe to retry.
|
Package idempotency makes non-idempotent operations (payments, orders, registrations) safe to retry. |
|
internal
|
|
|
binding
Package binding compiles per-type plans that bind request parameters (path, query, header, cookie) into struct fields.
|
Package binding compiles per-type plans that bind request parameters (path, query, header, cookie) into struct fields. |
|
capture
Package capture records a response while it is written to the client, so middleware can persist and replay it (response caching, idempotency).
|
Package capture records a response while it is written to the client, so middleware can persist and replay it (response caching, idempotency). |
|
Package jobs provides a common abstraction for background jobs: handlers, dispatching, worker lifecycle, retries with backoff, observability hooks and graceful shutdown.
|
Package jobs provides a common abstraction for background jobs: handlers, dispatching, worker lifecycle, retries with backoff, observability hooks and graceful shutdown. |
|
Package middleware provides Torge's optional official middleware.
|
Package middleware provides Torge's optional official middleware. |
|
Package openapi contains OpenAPI 3.1 document types and a schema generator that derives JSON Schemas from Go types, their json tags and their validate tags.
|
Package openapi contains OpenAPI 3.1 document types and a schema generator that derives JSON Schemas from Go types, their json tags and their validate tags. |
|
Package ratelimit provides rate limiting middleware with pluggable limiters.
|
Package ratelimit provides rate limiting middleware with pluggable limiters. |
|
Package realtime provides topic-based Server-Sent Events (SSE) broadcasting on top of Torge.
|
Package realtime provides topic-based Server-Sent Events (SSE) broadcasting on top of Torge. |
|
Package session provides server-side sessions referenced by a secure cookie.
|
Package session provides server-side sessions referenced by a secure cookie. |
|
Package sqldb adapts database/sql to Torge's database lifecycle: pooled connections with production defaults, health checks, graceful close and context-carried transactions.
|
Package sqldb adapts database/sql to Torge's database lifecycle: pooled connections with production defaults, health checks, graceful close and context-carried transactions. |
|
OpenAPI snapshot helpers for Torge tests: fetch the generated document in-process and compare it against a checked-in golden file.
|
OpenAPI snapshot helpers for Torge tests: fetch the generated document in-process and compare it against a checked-in golden file. |
|
Package upload handles multipart file uploads by streaming: parts are processed one at a time straight from the request body, so large files are never loaded into memory.
|
Package upload handles multipart file uploads by streaming: parts are processed one at a time straight from the request body, so large files are never loaded into memory. |
|
Package validate implements struct validation driven by `validate` struct tags.
|
Package validate implements struct validation driven by `validate` struct tags. |
|
Package webhook verifies incoming webhooks: signature verification over the exact raw body, timestamp validation, replay protection and structured errors, integrated with request IDs and logging.
|
Package webhook verifies incoming webhooks: signature verification over the exact raw body, timestamp validation, replay protection and structured errors, integrated with request IDs and logging. |