torge

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2026 License: MIT Imports: 39 Imported by: 0

README

Torge

CI Go Reference

A batteries-included backend framework for Go that makes serious backend development coherent without hiding Go. Handlers still see context.Context, error, *http.Request and http.ResponseWriter; the framework adds the production runtime around them.

  • Express-like simplicity — app.GET("/", handler) and app.Listen("") (listens on $PORT, like process.env.PORT || 8080).
  • Typed contracts — one struct declares binding, validation and the OpenAPI schema.
  • Unified lifecycle — config → dependencies → start hooks → serve → graceful shutdown, with startup diagnostics that say what, where, why and how to fix.
  • Production-safe defaults — timeouts, body limits, request IDs, structured access logs, panic recovery, security headers, health endpoints. The environment defaults to production when unset.
  • Replaceable infrastructure — databases, caches, queues, tracing and auth plug in through small interfaces. The core module has zero third-party dependencies.
package main

import (
	"log"

	"github.com/TosmimForidMehtab/torge"
)

func main() {
	app := torge.New()

	app.GET("/", func(c *torge.Context) error {
		return c.JSON(200, map[string]string{"message": "hello"})
	})

	if err := app.Listen(""); err != nil { // ":$PORT", or ":8080" when PORT is unset
		log.Fatal(err)
	}
}

Requires Go 1.26+.

go get github.com/TosmimForidMehtab/torge
go install github.com/TosmimForidMehtab/torge/cmd/torge@latest   # optional CLI

A realistic endpoint

type CreatePayment struct {
	Body struct {
		AccountID string `json:"account_id" validate:"required"`
		Amount    int64  `json:"amount"     validate:"gt=0,lte=1000000" doc:"Amount in cents"`
		Currency  string `json:"currency"   validate:"oneof=EUR USD GBP"`
	}
}

func (s *Payments) Create(c *torge.Context, in *CreatePayment) (*Payment, error) {
	acct, err := s.accounts.Get(c.Context(), in.Body.AccountID) // cancellation propagates
	if err != nil {
		return nil, err // *torge.Error renders as {"error":{"code":...}}; anything else as an opaque 500
	}
	return s.charge(c.Context(), acct, in.Body.Amount, in.Body.Currency)
}

// In a module:
torge.Post(api, "/payments", payments.Create,
	torge.Summary("Create a payment"),
	torge.Status(http.StatusCreated),
	idempotency.Middleware(idempotency.Config{Store: idempotency.NewStore(store), Required: true}),
)

Invalid input never reaches the handler: it gets a consistent 422 listing every failing field. The same struct produces the OpenAPI request schema with its constraints at /openapi.json, with interactive docs at /docs.

A serious application

var cfg Config
if err := config.Load(&cfg); err != nil { // typed env config, all problems reported at once
	log.Fatal(err)
}

app := torge.New(torge.WithTracing(torgeotel.Tracing()))
app.Config(&cfg)
app.Database(db)                   // pinged at startup, readiness check, closed last
app.Cache(torgeredis.NewStore(rdb))
app.Use(middleware.CORS(corsCfg), torgeotel.Metrics())
app.Register(AuthModule{}, UserModule{}, PaymentModule{})

log.Fatal(app.Listen(cfg.Addr))  // SIGTERM → drain → stop jobs → close deps → flush telemetry

The full, tested version lives in examples/production.

What's included

Concern Package Notes
App, routing, groups, middleware, context, errors, lifecycle, DI, modules, health, OpenAPI torge Core. Stdlib only.
Validation validate Tag rules, nested/dive, custom rules, Validatable.
Configuration config Env vars, defaults, required, validation, Secret type.
OpenAPI 3.1 types & schema generation openapi Driven by json, validate, doc, example tags.
Official middleware middleware CORS, Compress, Timeout, CSRF, Static, response Cache.
Authentication auth Bearer, API keys, Basic, policies (RequireRoles, RequireScopes).
Sessions session Server-side, fixation-safe, saved before headers.
Rate limiting ratelimit GCRA; by IP, user, route; memory limiter.
Idempotency idempotency Keys, fingerprints, replay, conflict detection.
Background jobs jobs Retries, backoff, dead letters, graceful stop; memory queue.
Cache cache Store contract, namespaces, LRU+TTL memory store, typed load-through.
HTTP client httpclient Timeouts, pooling, conservative retries, request ID propagation.
database/sql sqldb Pool defaults, context-carried transactions.
Webhooks webhook HMAC, Stripe, GitHub, Standard Webhooks; replay protection.
Uploads upload Streaming multipart, limits, sniffing, storage adapters.
Testing torgetest In-process client, assertions, test servers, middleware harness.
CLI cmd/torge new, dev, generate, routes, doctor, plugins. Optional.

Optional integrations are separate modules, so an HTTP-only application never downloads them:

Module Provides
contrib/otel Tracing and metrics middleware, client transport, job spans, shutdown flush (OpenTelemetry API).
contrib/redis Shared cache store, distributed GCRA limiter, reliable job queue (go-redis; Redis or Valkey).
contrib/jwt Bearer token verifier (golang-jwt) with mandatory algorithm allow-list.
contrib/pgx pgx pool lifecycle and context-carried transactions.
contrib/mongo MongoDB (official v2 driver) lifecycle and session-based transactions.
Staying lean
  • The core module has no dependencies beyond the Go standard library.
  • _test.go files are never compiled into applications. Tests that need test-only libraries (the OpenTelemetry SDK, miniredis) live in the separate contrib/tests module, so those libraries never appear in the dependency graph of applications using a contrib module.
  • examples/ and benchmarks/ are separate modules, excluded from the framework's download.

Testing

func TestCreateUser(t *testing.T) {
	app := torgetest.NewApp(t)
	app.Register(users.Module{})
	app.Replace(func() users.Store { return fakeStore{} }) // swap a dependency

	tc := torgetest.New(t, app)
	tc.POST("/users").JSON(map[string]string{"name": "Ada"}).Do().
		ExpectStatus(201).
		ExpectJSONPath("name", "Ada")
}

No network, no external processes; the whole suite runs with -race.

Documentation

Development

The repository is a Go workspace (go.work): the core module, one module per contrib integration, contrib/tests (contrib tests with test-only dependencies), examples and benchmarks.

go test -race ./...                         # core module
(cd contrib/redis && go test -race ./...)   # each contrib module
(cd contrib/tests && go test -race ./...)   # OpenTelemetry and Redis behavior
(cd examples && go test ./...)
(cd benchmarks && go test -bench . -benchmem)

Database integration tests run against real servers when configured: TORGE_TEST_POSTGRES_URL for contrib/pgx, TORGE_TEST_MONGO_URI (a replica set) for contrib/mongo.

Contributing

Contributions are welcome. Please read CONTRIBUTING.md and the Code of Conduct. Report security issues privately as described in SECURITY.md. Release notes are in CHANGELOG.md.

License

Torge is released under the MIT License.

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

View Source
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.

View Source
const (
	CodeBadRequest           = "BAD_REQUEST"
	CodeUnauthorized         = "UNAUTHORIZED"
	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"
	CodeServiceUnavailable   = "SERVICE_UNAVAILABLE"
	CodeTimeout              = "TIMEOUT"
	CodeRequestCanceled      = "REQUEST_CANCELED"
	CodeRouteNotFound        = "ROUTE_NOT_FOUND"
	CodeInvalidHost          = "INVALID_HOST"
	CodeNotImplemented       = "NOT_IMPLEMENTED"
	CodeUnprocessableContent = "UNPROCESSABLE_CONTENT"
)

Error codes used by the framework.

View Source
const (
	HealthUp       = "up"
	HealthDown     = "down"
	HealthStarting = "starting"
	HealthStopping = "stopping"
)

Health statuses.

View Source
const (
	Development = config.Development
	Test        = config.Test
	Production  = config.Production
)

Deployment environments.

View Source
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.

View Source
const DefaultBodyLimit = 4 << 20

DefaultBodyLimit is the default maximum request body size (4 MiB).

View Source
const DefaultPort = "8080"

DefaultPort is used by Listen("") when the PORT variable is unset.

View Source
const StatusClientClosedRequest = 499

StatusClientClosedRequest is the non-standard status used when the client disconnected before the response was written.

Variables

View Source
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

func DefaultErrorHandler(c *Context, err error)

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

func Dep[T any](c *Context) (T, error)

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

func ListenAddr(addr string) (string, error)

ListenAddr resolves an address the way Listen does: addr itself when non-empty, otherwise ":$PORT", otherwise ":8080".

func MustDep

func MustDep[T any](c *Context) T

MustDep is like Dep but panics on error (the panic is recovered and rendered as a 500 by the recovery stage).

func MustResolve

func MustResolve[T any](a *App) T

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

func ProblemErrorHandler(c *Context, err error)

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

func ReplaceValue[T any](a *App, v T)

ReplaceValue registers v under type T, replacing any existing provider. Intended for tests.

func Resolve

func Resolve[T any](a *App) (T, error)

Resolve returns the singleton of type T. It is available once the application has started (including inside Invoke functions).

func ServiceAs

func ServiceAs[T any](a *App, name string) (T, error)

ServiceAs returns the service registered under name as type T.

func StatusOf

func StatusOf(err error) int

StatusOf returns the HTTP status an error renders with.

func SupplyAs

func SupplyAs[T any](a *App, v T)

SupplyAs registers v under type T, typically an interface.

func UserAs

func UserAs[T Principal](c *Context) (T, bool)

UserAs returns the principal as type T.

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

func New(opts ...Option) *App

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

func (a *App) AddHook(h Hook)

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) AddTag

func (a *App) AddTag(tag openapi.Tag)

AddTag registers an OpenAPI tag description.

func (*App) Cache

func (a *App) Cache(store cache.Store)

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

func (a *App) Config(cfg any)

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) Env

func (a *App) Env() Env

Env returns the deployment environment.

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

func (a *App) Invoke(fn any)

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

func (a *App) Job(name string, h jobs.Handler, opts ...jobs.JobOption)

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

func (a *App) Jobs(m *jobs.Manager)

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

func (a *App) Listen(addr string) error

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) ListenTLS

func (a *App) ListenTLS(addr, certFile, keyFile string) error

ListenTLS is like Listen but serves HTTPS with the given certificate files.

func (*App) Logger

func (a *App) Logger() *slog.Logger

Logger returns the application logger. Records logged with a request context carry request_id and trace_id attributes.

func (*App) Manage

func (a *App) Manage(name string, l Lifecycle)

Manage registers a Lifecycle component.

func (*App) Modules

func (a *App) Modules() []string

Modules returns the names of registered modules.

func (*App) NewContext

func (a *App) NewContext(w http.ResponseWriter, r *http.Request) *Context

NewContext creates a Context for w and r outside the normal request pipeline. It is intended for tests and adapters.

func (*App) OnStart

func (a *App) OnStart(name string, fn func(context.Context) error)

OnStart registers a start callback.

func (*App) OnStop

func (a *App) OnStop(name string, fn func(context.Context) error)

OnStop registers a stop callback.

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

func (a *App) OpenAPIDocument() (*openapi.Document, error)

OpenAPIDocument returns the generated document. It is available after Start when OpenAPI is enabled.

func (*App) Options

func (a *App) Options() Options

Options returns a copy of the effective options.

func (*App) Pipeline

func (a *App) Pipeline() []string

Pipeline returns the names of the stages every request passes through, in order, including global middleware. Available after Start.

func (*App) PrintRoutes

func (a *App) PrintRoutes(w io.Writer) error

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

func (a *App) Register(mods ...Module)

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) Routes

func (a *App) Routes() []RouteInfo

Routes returns every registered route in registration order.

func (*App) Serve

func (a *App) Serve(ln net.Listener) error

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

func (a *App) Server() *http.Server

Server returns a configured *http.Server for this app, for callers that manage serving themselves.

func (*App) Service

func (a *App) Service(name string, svc any)

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) Services

func (a *App) Services() []string

Services returns the registered service names, sorted.

func (*App) SetLogger

func (a *App) SetLogger(l *slog.Logger)

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

func (a *App) Shutdown(ctx context.Context) error

Shutdown gracefully stops the application:

  1. readiness reports "stopping" (and the app waits DrainDelay);
  2. the server stops accepting connections and waits for in-flight requests;
  3. 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

func (a *App) Start(ctx context.Context) error

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) State

func (a *App) State() State

State returns the current lifecycle state.

func (*App) Supply

func (a *App) Supply(values ...any)

Supply registers ready-made values, keyed by their dynamic types. Supplied values are not lifecycle-managed.

func (*App) Transaction

func (a *App) Transaction(ctx context.Context, fn func(ctx context.Context) error) error

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.

func (*App) URL

func (a *App) URL(name string, params ...string) (string, error)

URL builds the path of a named route from name/value parameter pairs:

app.URL("user.get", "id", "42") // "/users/42"

func (*App) Validate

func (a *App) Validate() error

Validate runs the startup checks that do not require starting components and returns every problem found, or nil.

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

func (c *Context) Accepts(types ...string) string

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

func (c *Context) AddVary(value string)

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

func (c *Context) Attachment(path, filename string) error

Attachment serves a local file as a download named filename.

func (*Context) Bind

func (c *Context) Bind(dst any) error

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

func (c *Context) BindFormValues(dst any, values url.Values) error

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

func (c *Context) BindJSON(dst any) error

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) Bytes

func (c *Context) Bytes(status int, contentType string, b []byte) error

Bytes writes b with the given status and content type.

func (*Context) ClearCookie added in v0.3.0

func (c *Context) ClearCookie(name string)

ClearCookie expires the named cookie. The path defaults to "/", matching the common case for cookies set without an explicit path.

func (*Context) Context

func (c *Context) Context() 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) Cookie

func (c *Context) Cookie(name string) (*http.Cookie, error)

Cookie returns a request cookie.

func (*Context) Env

func (c *Context) Env() Env

Env returns the application environment.

func (*Context) File

func (c *Context) File(path string) error

File serves a file from the local filesystem, handling Range and conditional requests.

func (*Context) FileFS

func (c *Context) FileFS(fsys fs.FS, name string) error

FileFS serves name from fsys.

func (*Context) Flush

func (c *Context) Flush() error

Flush sends buffered response data to the client.

func (*Context) Format added in v0.3.0

func (c *Context) Format(offers ...Offer) error

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) Get

func (c *Context) Get(key any) (any, bool)

Get returns a value stored with Set.

func (*Context) GetHeader

func (c *Context) GetHeader(name string) string

GetHeader returns a request header.

func (*Context) HTML

func (c *Context) HTML(status int, html string) error

HTML writes an HTML response. The caller is responsible for escaping.

func (*Context) HandleError

func (c *Context) HandleError(err error)

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) Header

func (c *Context) Header(name, value string)

Header sets a response header.

func (*Context) Hostname added in v0.3.0

func (c *Context) Hostname() string

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

func (c *Context) Is(types ...string) bool

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

func (c *Context) IsFromTrustedProxy() bool

IsFromTrustedProxy reports whether the connection comes from a configured trusted proxy (see WithTrustedProxies).

func (*Context) JSON

func (c *Context) JSON(status int, v any) error

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 (c *Context) Links(links map[string]string)

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

func (c *Context) Location(url string)

Location sets the Location response header without changing the status. Pair it with Redirect or a 201 Created response.

func (*Context) Logger

func (c *Context) Logger() *slog.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) Method

func (c *Context) Method() string

Method returns the request method.

func (*Context) NoContent

func (c *Context) NoContent(code int) error

NoContent writes a response without a body, typically 204.

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) Param

func (c *Context) Param(name string) string

Param returns the value of a path parameter, or "".

func (*Context) Params

func (c *Context) Params() []Param

Params returns all path parameters in pattern order.

func (*Context) Path

func (c *Context) Path() string

Path returns the request URL path.

func (*Context) Query

func (c *Context) Query(name string) string

Query returns the first value of a query parameter, or "".

func (*Context) QueryDefault

func (c *Context) QueryDefault(name, def string) string

QueryDefault returns a query parameter or def if absent or empty.

func (*Context) QueryInt

func (c *Context) QueryInt(name string, def int) (int, error)

QueryInt parses a query parameter as an int, returning def when absent. A malformed value yields a 400 error.

func (*Context) QueryValues

func (c *Context) QueryValues() url.Values

QueryValues returns the parsed query string. The result is cached and must not be modified.

func (*Context) ReadBody

func (c *Context) ReadBody() ([]byte, error)

ReadBody reads the whole request body, subject to the body limit.

func (*Context) RealIP

func (c *Context) RealIP() string

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

func (c *Context) Redirect(code int, url string) error

Redirect replies with a redirect to url. code must be a 3xx status. Never redirect to unvalidated user input.

func (*Context) Request

func (c *Context) Request() *http.Request

Request returns the current *http.Request. Its context carries the request ID and the authenticated principal.

func (*Context) RequestID

func (c *Context) RequestID() string

RequestID returns the request ID, or "" if request IDs are disabled.

func (*Context) Response

func (c *Context) Response() *ResponseWriter

Response returns the response writer.

func (*Context) RouteName

func (c *Context) RouteName() string

RouteName returns the matched route's name, or "".

func (*Context) RoutePattern

func (c *Context) RoutePattern() string

RoutePattern returns the matched route pattern such as "/users/:id", or "" when no route matched.

func (*Context) SSE

func (c *Context) SSE() (*SSE, error)

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

func (c *Context) Scheme() string

Scheme returns "https" or "http". X-Forwarded-Proto is honored only from trusted proxies.

func (*Context) Secure added in v0.3.0

func (c *Context) Secure() bool

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

func (c *Context) Send(status int, v any) error

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

func (c *Context) Set(key, value any)

Set stores a request-scoped value for later middleware or the handler. Use an unexported key type to avoid collisions.

func (*Context) SetContext

func (c *Context) SetContext(ctx context.Context)

SetContext replaces the request's context. Middleware uses it to attach deadlines or values; ctx must derive from c.Context().

func (*Context) SetCookie

func (c *Context) SetCookie(cookie *http.Cookie)

SetCookie adds a Set-Cookie response header.

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

func (c *Context) SetRequest(r *http.Request)

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

func (c *Context) SetUser(p Principal)

SetUser records the authenticated principal. Authentication middleware calls it; the principal is also attached to c.Context() (see UserFrom).

func (*Context) Status

func (c *Context) Status(code int) error

Status writes only a status line and headers, with no body.

func (*Context) StatusCode

func (c *Context) StatusCode() int

StatusCode returns the status written so far, or 0.

func (*Context) Stream

func (c *Context) Stream(status int, contentType string, fn func(w io.Writer) error) error

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) String

func (c *Context) String(status int, s string) error

String writes a plain-text response.

func (*Context) Type added in v0.3.0

func (c *Context) Type(t string)

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.

func (*Context) User

func (c *Context) User() Principal

User returns the authenticated principal, or nil.

func (*Context) Validate

func (c *Context) Validate(v any) error

Validate validates v with the application's validator, converting failures into a 422 *Error with field details.

func (*Context) XHR added in v0.3.0

func (c *Context) XHR() bool

XHR reports whether the request was made by XMLHttpRequest.

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

type Database interface {
	Ping(ctx context.Context) error
	Close() error
}

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 Env

type Env = config.Env

Env is the deployment environment.

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

func AsError(err error) *Error

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 BadRequest

func BadRequest(code, message string) *Error

BadRequest returns a 400 error.

func Conflict

func Conflict(code, message string) *Error

Conflict returns a 409 error.

func Forbidden

func Forbidden(code, message string) *Error

Forbidden returns a 403 error.

func Internal

func Internal(code, message string) *Error

Internal returns a 500 error. Its message is still public, so keep it generic; put diagnostic information in the wrapped error.

func NewError

func NewError(status int, code, message string) *Error

NewError returns an Error with the given status, code and message.

func NotAcceptable added in v0.3.0

func NotAcceptable(code, message string) *Error

NotAcceptable returns a 406 error.

func NotFound

func NotFound(code, message string) *Error

NotFound returns a 404 error.

func ServiceUnavailable

func ServiceUnavailable(code, message string) *Error

ServiceUnavailable returns a 503 error.

func TooManyRequests

func TooManyRequests(code, message string) *Error

TooManyRequests returns a 429 error.

func Unauthorized

func Unauthorized(code, message string) *Error

Unauthorized returns a 401 error.

func UnprocessableEntity

func UnprocessableEntity(code, message string) *Error

UnprocessableEntity returns a 422 error.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface. The string contains internal details and is intended for logs.

func (*Error) Is

func (e *Error) Is(target error) bool

Is reports whether target is an *Error with the same Status and Code.

func (*Error) IsServerError

func (e *Error) IsServerError() bool

IsServerError reports whether the error represents a server-side failure.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the underlying cause.

func (*Error) WithDetails

func (e *Error) WithDetails(details any) *Error

WithDetails returns a copy of e with public details.

func (*Error) WithMessage

func (e *Error) WithMessage(msg string) *Error

WithMessage returns a copy of e with a different public message.

func (*Error) WithMeta

func (e *Error) WithMeta(key string, value any) *Error

WithMeta returns a copy of e with an internal metadata entry added.

func (*Error) Wrap

func (e *Error) Wrap(err error) *Error

Wrap returns a copy of e with err as its underlying cause.

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

type ErrorHandler func(c *Context, err error)

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) Prefix

func (g *Group) Prefix() string

Prefix returns the full path prefix of the group.

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

type Handler func(c *Context) error

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

func WrapHandler(h http.Handler) Handler

WrapHandler adapts a standard http.Handler. Use it to mount existing net/http components without rewriting them.

type HealthCheck

type HealthCheck func(ctx context.Context) error

HealthCheck reports whether a dependency is healthy. It must honor ctx.

type HealthChecker

type HealthChecker interface {
	CheckHealth(ctx context.Context) error
}

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.

func (JSONSerializer) Decode

func (s JSONSerializer) Decode(r io.Reader, v any) error

Decode implements Serializer.

func (JSONSerializer) Encode

func (JSONSerializer) Encode(w io.Writer, v any) error

Encode implements Serializer.

type Lifecycle

type Lifecycle interface {
	Start(context.Context) error
	Stop(context.Context) error
}

Lifecycle is implemented by components with explicit start and stop phases.

type Middleware

type Middleware func(next Handler) Handler

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

type Module interface {
	Register(app *App) error
}

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

type ModuleFunc func(app *App) error

ModuleFunc adapts a function to a Module.

func (ModuleFunc) Register

func (f ModuleFunc) Register(app *App) error

Register implements Module.

type NamedModule

type NamedModule interface {
	Module
	Name() string
}

NamedModule is a Module with an explicit name.

type Offer added in v0.3.0

type Offer struct {
	Name   string
	Handle Handler
}

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

func WithBodyLimit(n int64) Option

WithBodyLimit sets the default request body limit in bytes.

func WithEnv

func WithEnv(env Env) Option

WithEnv sets the deployment environment.

func WithErrorHandler

func WithErrorHandler(h ErrorHandler) Option

WithErrorHandler replaces the error renderer.

func WithExposeErrors

func WithExposeErrors(expose bool) Option

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 WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the application logger.

func WithRecovery

func WithRecovery(cfg *RecoveryConfig) Option

WithRecovery configures panic recovery. Pass nil to disable.

func WithRedirectTrailingSlash

func WithRedirectTrailingSlash(enabled bool) Option

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

func WithTrustedProxies(proxies ...string) Option

WithTrustedProxies sets the trusted reverse proxies (IPs or CIDRs).

func WithValidator

func WithValidator(v Validator) Option

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.

func (*Page[T]) HasNext added in v0.3.0

func (p *Page[T]) HasNext() bool

HasNext reports whether a page after the current one exists.

func (*Page[T]) HasPrev added in v0.3.0

func (p *Page[T]) HasPrev() bool

HasPrev reports whether a page before the current one exists.

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 Param

type Param struct {
	Name  string
	Value string
}

Param is a path parameter.

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.

func UserFrom

func UserFrom(ctx context.Context) Principal

UserFrom returns the principal attached to ctx by SetUser, or nil. Use it in services that receive only a context.Context.

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) Flush

func (w *ResponseWriter) Flush()

Flush implements http.Flusher.

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

type Result[T any] struct {
	Data T              `json:"data"`
	Meta map[string]any `json:"meta,omitempty"`
}

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.

func NewResult added in v0.3.0

func NewResult[T any](data T) *Result[T]

NewResult wraps data in a success envelope.

func (*Result[T]) WithMeta added in v0.3.0

func (r *Result[T]) WithMeta(key string, value any) *Result[T]

WithMeta attaches a metadata entry, allocating the map on first use. It returns the receiver for chaining.

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 Description

func Description(s string) RouteOption

Description sets the OpenAPI description.

func Hidden

func Hidden() RouteOption

Hidden excludes the route from the OpenAPI document.

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 Summary

func Summary(s string) RouteOption

Summary sets the OpenAPI summary.

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"))

func Tags

func Tags(tags ...string) RouteOption

Tags adds OpenAPI tags.

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.

func (*SSE) Comment

func (s *SSE) Comment(text string) error

Comment sends a comment line, commonly used as a keep-alive.

func (*SSE) Context

func (s *SSE) Context() context.Context

Context returns the request context.

func (*SSE) Done

func (s *SSE) Done() <-chan struct{}

Done is closed when the client disconnects or the request is canceled.

func (*SSE) Send

func (s *SSE) Send(e SSEEvent) error

Send writes one event and flushes it.

func (*SSE) SendJSON

func (s *SSE) SendJSON(event string, v any) error

SendJSON sends an event whose data is v encoded as JSON.

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 Scope

type Scope uint8

Scope controls how often a provider's constructor runs.

const (
	// SingletonScope constructs one value at startup, shared by the whole
	// application. Singleton values must be safe for concurrent use.
	SingletonScope Scope = iota
	// RequestScope constructs one value per request, on first use.
	RequestScope
)

func (Scope) String

func (s Scope) String() string
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

type Sort struct {
	Field string
	Desc  bool
}

Sort is a single validated sort clause: Field names a sortable field and Desc selects descending order.

func ParseSort added in v0.3.0

func ParseSort(param string, allowed ...string) ([]Sort, error)

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.

const (
	StateBuilding State = iota
	StateStarting
	StateRunning
	StateStopping
	StateStopped
	StateFailed
)

Lifecycle states.

func (State) String

func (s State) String() string

type Strict added in v0.3.0

type Strict = binding.Strict

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

type TypedHandler[I, O any] func(c *Context, in *I) (*O, error)

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.

type Validator

type Validator interface {
	Validate(v any) error
}

Validator validates decoded request values.

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.

Jump to

Keyboard shortcuts

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