router

package
v1.3.10 Latest Latest
Warning

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

Go to latest
Published: Dec 21, 2025 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package router provides a flexible and feature-rich HTTP routing framework. It supports middleware, sub-routers, generic handlers, and various configuration options.

Package router provides a flexible and feature-rich HTTP routing framework. It supports middleware, sub-routers, generic handlers, and various configuration options.

Index

Constants

View Source
const (
	// ParamsKey is the key used to store httprouter.Params in the request context.
	// This allows route parameters to be accessed from handlers and middleware.
	ParamsKey contextKey = "params"
)

Variables

This section is empty.

Functions

func ClientIPMiddleware added in v1.1.14

func ClientIPMiddleware[T comparable, U any](config *IPConfig) func(http.Handler) http.Handler

ClientIPMiddleware creates a middleware that extracts the client IP from the request and adds it to the SRouterContext. T is the User ID type (comparable), U is the User object type (any). It stores the IP address in the SRouterContext.

func GetParam

func GetParam(r *http.Request, name string) string

GetParam retrieves a specific parameter from the request context. It's a convenience function that combines GetParams and ByName.

func GetParams

func GetParams(r *http.Request) httprouter.Params

GetParams retrieves the httprouter.Params from the request context. This allows handlers to access route parameters extracted from the URL.

func RegisterGenericRoute

func RegisterGenericRoute[Req any, Resp any, UserID comparable, User any](
	r *Router[UserID, User],
	route RouteConfig[Req, Resp],

	effectiveTimeout time.Duration,
	effectiveMaxBodySize int64,
	effectiveRateLimit *common.RateLimitConfig[UserID, User],
)

RegisterGenericRoute registers a route with generic request and response types. This is a standalone function rather than a method because Go methods cannot have type parameters.

The function creates a complete request/response pipeline: 1. Decodes request using the codec (based on SourceType) 2. Applies optional sanitizer function 3. Calls the generic handler with decoded data 4. Encodes response using the codec 5. Handles errors appropriately (including HTTPError for custom status codes)

The effective settings (timeout, max body size, rate limit) must be pre-calculated by the caller. This is typically done by NewGenericRouteDefinition or RegisterGenericRouteOnSubRouter.

Note: This function is primarily for internal use. Users should prefer NewGenericRouteDefinition for declarative route registration within SubRouterConfig.

func RegisterGenericRouteOnSubRouter added in v1.1.2

func RegisterGenericRouteOnSubRouter[Req any, Resp any, UserID comparable, User any](
	r *Router[UserID, User],
	pathPrefix string,
	route RouteConfig[Req, Resp],
) error

RegisterGenericRouteOnSubRouter registers a generic route on a specific sub-router after router creation. This function is primarily used for dynamic route registration after the router has been initialized. For static route configuration, prefer using NewGenericRouteDefinition within SubRouterConfig.Routes.

The function locates the sub-router by path prefix, applies its configuration (middleware, timeouts, rate limits), and registers the route with the combined settings.

Type parameters:

  • Req: Request type for the route
  • Resp: Response type for the route
  • UserID: Must match the router's T type parameter
  • User: Must match the router's U type parameter

Returns an error if no sub-router with the given prefix exists.

Note: This is considered an advanced use case. The preferred approach is declarative route registration using NewGenericRouteDefinition in SubRouterConfig.

func RegisterSubRouterWithSubRouter added in v1.0.7

func RegisterSubRouterWithSubRouter(parent *SubRouterConfig, child SubRouterConfig)

RegisterSubRouterWithSubRouter registers a nested SubRouter with a parent SubRouter. This helper function enables hierarchical route organization by adding a child SubRouter to the parent's SubRouters slice.

Important behaviors: - Path prefixes are concatenated (parent + child) - Configuration overrides are NOT inherited - the child must set its own - Middlewares will be combined additively when routes are registered - This modifies the parent SubRouterConfig by appending to its SubRouters slice

Example:

parentRouter := SubRouterConfig{PathPrefix: "/api"}
childRouter := SubRouterConfig{PathPrefix: "/v1", Overrides: common.RouteOverrides{Timeout: 5*time.Second}}
RegisterSubRouterWithSubRouter(&parentRouter, childRouter)
// Results in routes under /api/v1 with the child's timeout override

Types

type AuthLevel added in v1.0.0

type AuthLevel int

AuthLevel defines the authentication level for a route. It determines how authentication is handled for the route.

const (
	// NoAuth indicates that no authentication is required for the route.
	// The route will be accessible without any authentication.
	NoAuth AuthLevel = iota

	// AuthOptional indicates that authentication is optional for the route.
	// If authentication credentials are provided, they will be validated and the user
	// will be added to the request context if valid. If no credentials are provided
	// or they are invalid, the request will still proceed without a user in the context.
	AuthOptional

	// AuthRequired indicates that authentication is required for the route.
	// If authentication fails, the request will be rejected with a 401 Unauthorized response.
	// If authentication succeeds, the user will be added to the request context.
	AuthRequired
)

func Ptr added in v1.1.2

func Ptr(level AuthLevel) *AuthLevel

Ptr returns a pointer to the given AuthLevel value. Useful for setting AuthLevel fields in configurations.

type CORSConfig added in v1.2.7

type CORSConfig struct {
	Origins          []string      // Allowed origins (e.g., "http://example.com", "*"). Required.
	Methods          []string      // Allowed methods (e.g., "GET", "POST"). Defaults to simple methods if empty.
	Headers          []string      // Allowed headers. Defaults to simple headers if empty.
	ExposeHeaders    []string      // Headers the browser is allowed to access.
	AllowCredentials bool          // Whether to allow credentials (cookies, authorization headers).
	MaxAge           time.Duration // How long the results of a preflight request can be cached.
}

CORSConfig defines the configuration for Cross-Origin Resource Sharing (CORS). It allows customization of which origins, methods, headers, and credentials are allowed for cross-origin requests, and which headers can be exposed to the client-side script.

type GenericHandler

type GenericHandler[T any, U any] func(r *http.Request, data T) (U, error)

GenericHandler defines a handler function with generic request and response types. It takes an http.Request and a typed request data object, and returns a typed response object and an error. This allows for strongly-typed request and response handling. The type parameters T and U represent the request and response data types respectively. When used with RegisterGenericRoute, the framework automatically handles decoding the request and encoding the response using the specified Codec.

type GenericRouteRegistrationFunc added in v1.1.2

type GenericRouteRegistrationFunc[T comparable, U any] func(r *Router[T, U], sr SubRouterConfig)

GenericRouteRegistrationFunc defines the function signature for registering a generic route declaratively. This function is stored in SubRouterConfig.Routes and called during router initialization. It receives the router instance and the SubRouterConfig it belongs to, allowing it to: - Calculate effective settings based on sub-router configuration - Apply the sub-router's path prefix - Combine middlewares appropriately - Register the route with all settings applied

This type is used internally by NewGenericRouteDefinition.

func NewGenericRouteDefinition added in v1.1.2

func NewGenericRouteDefinition[Req any, Resp any, UserID comparable, User any](
	route RouteConfig[Req, Resp],
) GenericRouteRegistrationFunc[UserID, User]

NewGenericRouteDefinition creates a GenericRouteRegistrationFunc for declarative configuration. It captures the specific RouteConfig[Req, Resp] and returns a function that, when called by registerSubRouter, calculates effective settings and registers the generic route.

This is the recommended way to register generic routes within SubRouterConfig.Routes. It ensures proper application of sub-router settings including: - Path prefix concatenation - Middleware combination (sub-router + route-specific) - Configuration override precedence - AuthLevel inheritance (route > sub-router > default)

Type parameters must match those used in NewRouter[UserID, User].

type HTTPError

type HTTPError struct {
	StatusCode int    // HTTP status code (e.g., 400, 404, 500)
	Message    string // Error message to be sent in the response body
}

HTTPError represents an HTTP error with a status code and message. It can be used to return specific HTTP errors from handlers. When returned from a handler, the router will use the status code and message to generate an appropriate HTTP response. This allows handlers to control the exact error response sent to clients.

func NewHTTPError

func NewHTTPError(statusCode int, message string) *HTTPError

NewHTTPError creates a new HTTPError with the specified status code and message. It's a convenience function for creating HTTP errors in handlers.

func (*HTTPError) Error

func (e *HTTPError) Error() string

Error implements the error interface. It returns a string representation of the HTTP error in the format "status: message".

type HttpMethod added in v1.1.11

type HttpMethod string

HttpMethod defines the type for HTTP methods.

const (
	MethodGet     HttpMethod = http.MethodGet
	MethodHead    HttpMethod = http.MethodHead
	MethodPost    HttpMethod = http.MethodPost
	MethodPut     HttpMethod = http.MethodPut
	MethodPatch   HttpMethod = http.MethodPatch // RFC 5789
	MethodDelete  HttpMethod = http.MethodDelete
	MethodConnect HttpMethod = http.MethodConnect
	MethodOptions HttpMethod = http.MethodOptions
	MethodTrace   HttpMethod = http.MethodTrace
)

Constants for standard HTTP methods.

type IPConfig added in v1.1.14

type IPConfig struct {
	// Source specifies where to extract the client IP from.
	Source IPSourceType

	// CustomHeader is the name of the custom header to use when Source is IPSourceCustomHeader
	CustomHeader string

	// TrustProxy determines whether to trust proxy headers like X-Forwarded-For
	// If false, RemoteAddr will be used as a fallback for all sources
	TrustProxy bool
}

IPConfig defines configuration for IP extraction.

func DefaultIPConfig added in v1.1.14

func DefaultIPConfig() *IPConfig

DefaultIPConfig returns the default IP configuration.

type IPSourceType added in v1.1.14

type IPSourceType string

IPSourceType defines the source for client IP addresses.

const (
	// IPSourceRemoteAddr uses the request's RemoteAddr field
	IPSourceRemoteAddr IPSourceType = "remote_addr"

	// IPSourceXForwardedFor uses the X-Forwarded-For header
	IPSourceXForwardedFor IPSourceType = "x_forwarded_for"

	// IPSourceXRealIP uses the X-Real-IP header
	IPSourceXRealIP IPSourceType = "x_real_ip"

	// IPSourceCustomHeader uses a custom header specified in the configuration
	IPSourceCustomHeader IPSourceType = "custom_header"
)

type MetricsConfig added in v1.0.3

type MetricsConfig struct {
	// Collector is the metrics collector to use.
	// If nil, a default collector will be used if metrics are enabled.
	Collector any // metrics.Collector

	// MiddlewareFactory is the factory for creating metrics middleware.
	// If nil, a default middleware factory will be used if metrics are enabled.
	MiddlewareFactory any // metrics.MiddlewareFactory

	// Namespace for metrics.
	Namespace string

	// Subsystem for metrics.
	Subsystem string

	// EnableLatency enables latency metrics.
	EnableLatency bool

	// EnableThroughput enables throughput metrics.
	EnableThroughput bool

	// EnableQPS enables queries per second metrics.
	EnableQPS bool

	// EnableErrors enables error metrics.
	EnableErrors bool
}

MetricsConfig defines the configuration for metrics collection. It allows customization of how metrics are collected and exposed.

type RouteConfig

type RouteConfig[T any, U any] struct {
	Path        string                // Route path (will be prefixed with sub-router path prefix if applicable)
	Methods     []HttpMethod          // HTTP methods this route handles (use constants like MethodGet)
	AuthLevel   *AuthLevel            // Authentication level for this route. If nil, inherits from sub-router or defaults to NoAuth
	Overrides   common.RouteOverrides // Configuration overrides for this specific route
	Codec       codec.Codec[T, U]     // Codec for marshaling/unmarshaling request and response (required)
	Handler     GenericHandler[T, U]  // Generic handler function (required)
	Middlewares []common.Middleware   // Middlewares applied to this specific route (combined with sub-router and global middlewares)
	SourceType  SourceType            // Where to retrieve request data from (defaults to Body)
	SourceKey   string                // Parameter name for query/path parameters (required when SourceType is not Body/Empty)
	Sanitizer   func(T) (T, error)    // Optional function to validate/transform request data after decoding
}

RouteConfig defines a route with generic request and response types. It provides type-safe request/response handling with automatic marshaling/unmarshaling. The framework handles decoding the request into type T and encoding the response of type U.

Configuration precedence (when used within a sub-router): - Route settings override sub-router settings - Sub-router settings override global settings - Middlewares are additive (not replaced)

Use NewGenericRouteDefinition to register these routes within SubRouterConfig.Routes.

type RouteConfigBase

type RouteConfigBase struct {
	Path           string                // Route path (will be prefixed with sub-router path prefix if applicable)
	Methods        []HttpMethod          // HTTP methods this route handles (use constants like MethodGet)
	AuthLevel      *AuthLevel            // Authentication level for this route. If nil, inherits from sub-router or defaults to NoAuth
	Overrides      common.RouteOverrides // Configuration overrides for this specific route
	Handler        http.HandlerFunc      // Standard HTTP handler function
	Middlewares    []common.Middleware   // Middlewares applied to this specific route (combined with sub-router and global middlewares)
	DisableTimeout bool                  // Indicates if the timeout should be disabled for this route (e.g., for WebSockets or long-lived connections).
}

RouteConfigBase defines the base configuration for a standard (non-generic) route. It includes settings for path, HTTP methods, authentication, timeouts, and middleware. This is used for routes that work directly with http.ResponseWriter and *http.Request.

Configuration precedence (when used within a sub-router): - Route settings override sub-router settings - Sub-router settings override global settings - Middlewares are additive (not replaced)

type RouteDefinition added in v1.3.1

type RouteDefinition interface {
	// contains filtered or unexported methods
}

RouteDefinition is an interface that all route types must implement. This allows SubRouterConfig.Routes to store both standard and generic routes in a type-safe manner.

type Router

type Router[T comparable, U any] struct {
	// contains filtered or unexported fields
}

Router is the main router struct that implements http.Handler. It provides routing, middleware support, graceful shutdown, and other features.

func NewRouter

func NewRouter[T comparable, U any](config RouterConfig, authFunction func(context.Context, string) (*U, bool), userIdFromuserFunction func(*U) T) *Router[T, U]

NewRouter creates a new Router instance with the given configuration. It initializes all components including the underlying httprouter, logging, middleware, metrics, rate limiting, and registers all routes defined in the configuration.

Type parameters:

  • T: The user ID type (must be comparable, e.g., string, int, uuid.UUID)
  • U: The user object type (e.g., User, Account)

Parameters:

  • config: Router configuration including sub-routers, middleware, and settings
  • authFunction: Function to validate tokens and return user objects
  • userIdFromuserFunction: Function to extract user ID from user object

The router automatically sets up trace ID generation, metrics collection, and CORS handling based on the provided configuration.

func (*Router[T, U]) RegisterRoute

func (r *Router[T, U]) RegisterRoute(route RouteConfigBase)

RegisterRoute registers a standard (non-generic) route with the router. It creates a handler with all middlewares applied and registers it with the underlying httprouter.

Middleware execution order: 1. Global middlewares (from RouterConfig) 2. Route-specific middlewares

Configuration precedence (most specific wins): - Route settings > Global settings

For generic routes with type parameters, use RegisterGenericRoute function instead.

func (*Router[T, U]) RegisterSubRouter added in v1.0.7

func (r *Router[T, U]) RegisterSubRouter(sr SubRouterConfig)

RegisterSubRouter registers a sub-router with the router after router creation. This method allows dynamic registration of sub-routers at runtime.

The sub-router's configuration is applied as follows: - Path prefix is prepended to all routes in the sub-router - Middlewares are added to (not replacing) global middlewares - Configuration overrides (timeout, max body size, rate limit) apply only to direct routes - Nested sub-routers will have their path prefixes concatenated but must set their own overrides

This is useful for conditionally adding routes or building routes programmatically.

func (*Router[T, U]) ServeHTTP

func (r *Router[T, U]) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP implements the http.Handler interface. It handles HTTP requests by applying CORS, client IP extraction, metrics, tracing, and then delegating to the underlying httprouter.

func (*Router[T, U]) Shutdown

func (r *Router[T, U]) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the router. It stops accepting new requests and waits for existing requests to complete.

type RouterConfig

type RouterConfig struct {
	ServiceName         string                            // Name of the service, used for metrics tagging etc.
	Logger              *zap.Logger                       // Logger for all router operations
	GlobalTimeout       time.Duration                     // Default response timeout for all routes
	GlobalMaxBodySize   int64                             // Default maximum request body size in bytes
	GlobalRateLimit     *common.RateLimitConfig[any, any] // Use common.RateLimitConfig // Default rate limit for all routes
	IPConfig            *IPConfig                         // Configuration for client IP extraction
	EnableTraceLogging  bool                              // Enable trace logging
	TraceLoggingUseInfo bool                              // Use Info level for trace logging
	TraceIDBufferSize   int                               // Buffer size for trace ID generator (0 disables trace ID)
	MetricsConfig       *MetricsConfig                    // Metrics configuration (optional)
	SubRouters          []SubRouterConfig                 // Sub-routers with their own configurations
	Middlewares         []common.Middleware               // Global middlewares applied to all routes
	AddUserObjectToCtx  bool                              // Add user object to context
	CORSConfig          *CORSConfig                       // CORS configuration (optional, if nil CORS is disabled)
}

RouterConfig defines the global configuration for the router. It includes settings for logging, timeouts, metrics, and middleware.

type SourceType added in v1.0.5

type SourceType int

SourceType defines where to retrieve request data from. It determines how the request data is extracted and decoded.

const (
	// Body retrieves data from the request body (default).
	// The request body is read and passed directly to the codec for decoding.
	Body SourceType = iota

	// Base64QueryParameter retrieves data from a base64-encoded query parameter.
	// The query parameter value is decoded from base64 before being passed to the codec.
	Base64QueryParameter

	// Base62QueryParameter retrieves data from a base62-encoded query parameter.
	// The query parameter value is decoded from base62 before being passed to the codec.
	Base62QueryParameter

	// Base64PathParameter retrieves data from a base64-encoded path parameter.
	// The path parameter value is decoded from base64 before being passed to the codec.
	Base64PathParameter

	// Base62PathParameter retrieves data from a base62-encoded path parameter.
	// The path parameter value is decoded from base62 before being passed to the codec.
	Base62PathParameter

	// Empty does not decode anything. It acts as a noop for decoding.
	Empty
)

type SubRouterConfig

type SubRouterConfig struct {
	PathPrefix  string                // Common path prefix for all routes in this sub-router
	Overrides   common.RouteOverrides // Configuration overrides for routes in this sub-router (not inherited by nested sub-routers)
	Routes      []RouteDefinition     // Routes in this sub-router. Can contain RouteConfigBase or GenericRouteRegistrationFunc
	Middlewares []common.Middleware   // Middlewares applied to all routes in this sub-router (additive with global middlewares)
	// SubRouters is a slice of nested sub-routers.
	// Nested sub-routers inherit the parent's path prefix (concatenated) but NOT configuration overrides.
	// Each nested sub-router must explicitly set its own overrides if needed.
	SubRouters []SubRouterConfig // Nested sub-routers with concatenated path prefixes
	AuthLevel  *AuthLevel        // Default authentication level for all routes in this sub-router (overridden by route-specific AuthLevel)
}

SubRouterConfig defines configuration for a group of routes with a common path prefix. This allows for organizing routes into logical groups and applying shared configuration. Sub-routers can be nested to create hierarchical routing structures with concatenated path prefixes.

Important behaviors: - Path prefixes are concatenated when nesting (e.g., "/api" + "/v1" = "/api/v1") - Configuration overrides (timeout, max body size, rate limit) are NOT inherited by nested sub-routers - Middlewares are additive - they combine with parent and global middlewares - Routes can be added declaratively via the Routes field or imperatively after router creation

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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