Documentation
¶
Overview ¶
Package srv provides HTTP server utilities with middleware support, graceful shutdown, enhanced routing with URL reversing, and standardized error handling via the erm package.
This package offers a collection of HTTP middleware components, a server runner that supports graceful shutdown with signal handling, and an enhanced router with URL reversing capabilities. It includes logging and recovery middleware, along with utilities for chaining multiple middleware together. All errors use the erm package for consistent HTTP status codes and internationalized error messages.
Example usage:
mux := srv.NewMux()
mux.Get("users", "/users", func(ctx srv.Context) error {
return ctx.JSON(200, users)
})
mux.Get("user", "/users/{id}", func(ctx srv.Context) error {
id := ctx.Param("id")
editURL, _ := mux.Reverse("user", map[string]string{"id": id})
return ctx.JSON(200, map[string]interface{}{
"user": getUser(id),
"edit_url": editURL,
})
})
// Chain middleware using the Mux Middleware method
mux.Middleware(srv.LoggingMiddleware)
mux.Middleware(srv.RecoverMiddleware)
// Run server with graceful shutdown
err := srv.RunServer(handler, "localhost", "8080", func() error {
// cleanup logic here
return nil
})
Index ¶
- Constants
- Variables
- func ParseRequest(r *http.Request, target interface{}) erm.Error
- func RunServer(handler http.Handler, host string, port string, cleanup func() error) error
- type CORSConfig
- type Context
- type CookieStore
- type HandlerFunc
- type HandlerFuncMiddleware
- type HttpContext
- func (c *HttpContext) AddHeader(key, value string)
- func (c *HttpContext) Cookie(key string) (*http.Cookie, error)
- func (c *HttpContext) Cookies() []*http.Cookie
- func (c *HttpContext) FormValue(key string) string
- func (c *HttpContext) Get(key string) interface{}
- func (c *HttpContext) GetHeader(key string) string
- func (c *HttpContext) GetHeaders() http.Header
- func (c *HttpContext) HTML(code int, html string) error
- func (c *HttpContext) HTMLBlob(code int, blob []byte) error
- func (c *HttpContext) IsTLS() bool
- func (c *HttpContext) IsWebSocket() bool
- func (c *HttpContext) JSON(code int, v interface{}) error
- func (c *HttpContext) Method() string
- func (c *HttpContext) Param(key string) string
- func (c *HttpContext) Path() string
- func (c *HttpContext) Query() url.Values
- func (c *HttpContext) QueryParam(key string) string
- func (c *HttpContext) Redirect(code int, url string) error
- func (c *HttpContext) Request() *http.Request
- func (c *HttpContext) Response() http.ResponseWriter
- func (c *HttpContext) Set(key string, value interface{})
- func (c *HttpContext) SetCookie(cookie *http.Cookie)
- func (c *HttpContext) SetHeader(key, value string)
- func (c *HttpContext) SetPath(path string)
- func (c *HttpContext) String(code int, text string) error
- func (c *HttpContext) WriteHeader(code int)
- type InMemoryStore
- type Mux
- func (m *Mux) Delete(name, pattern string, handler HandlerFunc)
- func (m *Mux) ErrorHandler(handler func(c Context, err error))
- func (m *Mux) Get(name, pattern string, handler HandlerFunc)
- func (m *Mux) Handle(pattern string, handler http.Handler)
- func (m *Mux) HandleFunc(pattern string, handler http.HandlerFunc)
- func (m *Mux) Head(name, pattern string, handler HandlerFunc)
- func (m *Mux) Middleware(middleware HandlerFuncMiddleware)
- func (m *Mux) Mux() *http.ServeMux
- func (m *Mux) Options(name, pattern string, handler HandlerFunc)
- func (m *Mux) Patch(name, pattern string, handler HandlerFunc)
- func (m *Mux) Post(name, pattern string, handler HandlerFunc)
- func (m *Mux) Put(name, pattern string, handler HandlerFunc)
- func (m *Mux) Reverse(name string, params map[string]string) (string, error)
- func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request)
- type Options
- type Route
- type Session
- type Store
- type TrailingSlashConfig
Constants ¶
const ( // MIMEApplicationJSON JavaScript Object Notation (JSON) https://www.rfc-editor.org/rfc/rfc8259 MIMEApplicationJSON = "application/json" MIMEApplicationJavaScript = "application/javascript" MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8 MIMEApplicationXML = "application/xml" MIMEApplicationXMLCharsetUTF8 = MIMEApplicationXML + "; " + charsetUTF8 MIMETextXML = "text/xml" MIMETextXMLCharsetUTF8 = MIMETextXML + "; " + charsetUTF8 MIMEApplicationForm = "application/x-www-form-urlencoded" MIMEApplicationProtobuf = "application/protobuf" MIMEApplicationMsgpack = "application/msgpack" MIMETextHTML = "text/html" MIMETextHTMLCharsetUTF8 = MIMETextHTML + "; " + charsetUTF8 MIMETextPlain = "text/plain" MIMETextPlainCharsetUTF8 = MIMETextPlain + "; " + charsetUTF8 MIMEMultipartForm = "multipart/form-data" MIMEOctetStream = "application/octet-stream" )
const ( HeaderAccept = "Accept" HeaderAcceptEncoding = "Accept-Encoding" // HeaderAllow is the name of the "Allow" header field used to list the set of methods // advertised as supported by the target resource. Returning an Allow header is mandatory // for status 405 (method not found) and useful for the OPTIONS method in responses. // See RFC 7231: https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1 HeaderAllow = "Allow" HeaderAuthorization = "Authorization" HeaderContentDisposition = "Content-Disposition" HeaderContentEncoding = "Content-Encoding" HeaderContentLength = "Content-Length" HeaderContentType = "Content-Type" HeaderCookie = "Cookie" HeaderSetCookie = "Set-Cookie" HeaderIfModifiedSince = "If-Modified-Since" HeaderLastModified = "Last-Modified" HeaderLocation = "Location" HeaderRetryAfter = "Retry-After" HeaderUpgrade = "Upgrade" HeaderVary = "Vary" HeaderWWWAuthenticate = "WWW-Authenticate" HeaderXForwardedFor = "X-Forwarded-For" HeaderXForwardedProto = "X-Forwarded-Proto" HeaderXForwardedProtocol = "X-Forwarded-Protocol" HeaderXForwardedSsl = "X-Forwarded-Ssl" HeaderXUrlScheme = "X-Url-Scheme" HeaderXHTTPMethodOverride = "X-HTTP-Method-Override" HeaderXRealIP = "X-Real-Ip" HeaderXRequestID = "X-Request-Id" HeaderXCorrelationID = "X-Correlation-Id" HeaderXRequestedWith = "X-Requested-With" HeaderServer = "Server" HeaderOrigin = "Origin" HeaderCacheControl = "Cache-Control" HeaderConnection = "Connection" // Access control HeaderAccessControlRequestMethod = "Access-Control-Request-Method" HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers" HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin" HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods" HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers" HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials" HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers" HeaderAccessControlMaxAge = "Access-Control-Max-Age" // Security HeaderStrictTransportSecurity = "Strict-Transport-Security" HeaderXContentTypeOptions = "X-Content-Type-Options" HeaderXXSSProtection = "X-XSS-Protection" HeaderXFrameOptions = "X-Frame-Options" HeaderContentSecurityPolicy = "Content-Security-Policy" HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only" HeaderXCSRFToken = "X-CSRF-Token" HeaderReferrerPolicy = "Referrer-Policy" )
Variables ¶
var DefaultCORSConfig = CORSConfig{ AllowOrigins: []string{"*"}, AllowMethods: []string{ http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete, http.MethodOptions, }, AllowHeaders: []string{}, AllowCredentials: false, ExposeHeaders: []string{}, MaxAge: 0, }
DefaultCORSConfig is the default CORS middleware config.
var DefaultTrailingSlashConfig = TrailingSlashConfig{
RedirectCode: 0,
}
DefaultTrailingSlashConfig is the default AddTrailingSlash middleware config.
Functions ¶
func ParseRequest ¶
ParseRequest parses HTTP request payload (JSON or form data) and query parameters into the provided target structure This function automatically detects the Content-Type and uses the appropriate parsing method for the request body, while also parsing URL query parameters regardless of Content-Type
Supported Content-Types: - application/json: Uses json.NewDecoder for efficient streaming - application/x-www-form-urlencoded: Parses form data using reflection and struct tags - multipart/form-data: Parses multipart form data - Empty Content-Type: Attempts to detect based on request body
Features: - Automatic Content-Type detection and routing - Efficient JSON streaming (like json/v2.UnmarshalRead pattern) - Form field mapping using `form` struct tags - Query parameter mapping using `query` struct tags - Type conversion for form and query values (string, int, bool, etc.) - Custom type support for types implementing encoding.TextUnmarshaler interface - Proper error handling with erm.Error types - Resource leak prevention with automatic cleanup - Combined parsing: both request body and query parameters in single call
Example usage:
type UserID [16]byte
func (u *UserID) UnmarshalText(text []byte) error {
if len(text) != 32 { // hex encoded 16 bytes
return errors.New("invalid UserID length")
}
_, err := hex.Decode(u[:], text)
return err
}
type CreateUserRequest struct {
Name string `json:"name" form:"name"`
Email string `json:"email" form:"email"`
Age int `json:"age" form:"age"`
UserID UserID `form:"user_id" query:"user_id"` // Custom type with TextUnmarshaler
Page int `query:"page"`
Sort string `query:"sort"`
FilterBy string `query:"filter_by"`
}
var req CreateUserRequest
if err := ParseRequest(r, &req); err != nil {
// Handle error
return err
}
// Use req.Name, req.Email, req.Age (from body)
// Use req.UserID (parsed via UnmarshalText), req.Page, req.Sort, req.FilterBy (from query parameters)
func RunServer ¶
RunServer starts an HTTP server with graceful shutdown capabilities. It listens on the specified host and port, and shuts down gracefully when receiving SIGINT or SIGTERM signals.
Parameters:
- handler: The HTTP handler to serve requests
- host: The host to bind to (defaults to "0.0.0.0" if empty)
- port: The port to listen on (defaults to "8000" if empty)
- cleanup: A function called during shutdown for resource cleanup
The server performs the following shutdown sequence:
- Receives shutdown signal (SIGINT/SIGTERM)
- Stops accepting new requests
- Waits up to 10 seconds for existing requests to complete
- Calls the cleanup function
- Returns any errors that occurred
Returns an error if the server fails to start or if shutdown encounters an error.
Example:
err := RunServer(handler, "localhost", "8080", func() error {
// Close database connections, cleanup resources, etc.
return db.Close()
})
if err != nil {
log.Fatal(err)
}
Types ¶
type CORSConfig ¶
type CORSConfig struct {
// AllowOrigins determines the value of the Access-Control-Allow-Origin
// response header. This header defines a list of origins that may access the
// resource. The wildcard characters '*' and '?' are supported and are
// converted to regex fragments '.*' and '.' accordingly.
//
// Security: use extreme caution when handling the origin, and carefully
// validate any logic. Remember that attackers may register hostile domain names.
//
// Optional. Default value []string{"*"}.
AllowOrigins []string
// AllowMethods determines the value of the Access-Control-Allow-Methods
// response header. This header specifies the list of methods allowed when
// accessing the resource. This is used in response to a preflight request.
//
// Optional. Default value []string{"GET", "HEAD", "PUT", "PATCH", "POST", "DELETE", "OPTIONS"}.
AllowMethods []string
// AllowHeaders determines the value of the Access-Control-Allow-Headers
// response header. This header is used in response to a preflight request to
// indicate which HTTP headers can be used when making the actual request.
//
// Optional. Default value []string{}.
AllowHeaders []string
// AllowCredentials determines the value of the Access-Control-Allow-Credentials
// response header. This header indicates whether or not the response to the
// request can be exposed when the credentials mode is true.
//
// Optional. Default value false.
// Security: avoid using AllowCredentials = true with AllowOrigins = "*".
AllowCredentials bool
// ExposeHeaders determines the value of Access-Control-Expose-Headers, which
// defines a list of headers that clients are allowed to access.
//
// Optional. Default value []string{}.
ExposeHeaders []string
// MaxAge determines the value of the Access-Control-Max-Age response header.
// This header indicates how long (in seconds) the results of a preflight
// request can be cached.
//
// Optional. Default value 0 - meaning header is not sent.
MaxAge int
}
CORSConfig defines the configuration for CORS middleware.
type Context ¶
type Context interface {
Set(key string, value interface{})
Get(key string) interface{}
Request() *http.Request
Response() http.ResponseWriter
IsTLS() bool
IsWebSocket() bool
Method() string
Path() string
Param(key string) string
Query() url.Values
QueryParam(key string) string
FormValue(key string) string
GetHeader(key string) string
GetHeaders() http.Header
Cookie(key string) (*http.Cookie, error)
Cookies() []*http.Cookie
SetHeader(key, value string)
AddHeader(key, value string)
SetCookie(cookie *http.Cookie)
JSON(code int, v interface{}) error
String(code int, text string) error
Redirect(code int, path string) error
HTML(code int, html string) error
HTMLBlob(code int, html []byte) error
WriteHeader(code int)
}
type CookieStore ¶
type CookieStore struct {
// contains filtered or unexported fields
}
CookieStore provides an encrypted cookie-based session store implementation. It stores all session data directly in encrypted cookies on the client side, eliminating the need for server-side session storage.
The store uses AES-GCM encryption for authenticated encryption, ensuring both confidentiality and integrity of session data. Session values are serialized using gob encoding before encryption.
This implementation is suitable for stateless applications or when you want to avoid server-side session storage. However, be aware of cookie size limits (typically ~4KB) and ensure your session data fits within these constraints.
func NewCookieStore ¶
func NewCookieStore(name string, key []byte, options *Options) (*CookieStore, error)
NewCookieStore creates a new cookie-based session store with the specified encryption key and options. The encryption key must be 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 respectively.
The store uses AES-GCM for authenticated encryption, providing both confidentiality and integrity protection for session data.
Example usage:
// Generate a 32-byte key for AES-256
key := make([]byte, 32)
if _, err := rand.Read(key); err != nil {
log.Fatal(err)
}
// Create cookie store
store, err := srv.NewCookieStore("app-session", key, srv.NewOptions())
if err != nil {
log.Fatal(err)
}
// Use with session middleware
mux.Middleware(srv.SessionMiddleware(store, "app-session"))
func (*CookieStore) Get ¶
Get retrieves an existing session from the encrypted cookie. If the cookie doesn't exist, is invalid, or cannot be decrypted, it returns an error.
func (*CookieStore) New ¶
New creates a new session. Since this is a cookie store, no server-side storage is required. The session will be saved as an encrypted cookie when Save() is called.
func (*CookieStore) Save ¶
func (c *CookieStore) Save(_ *http.Request, w http.ResponseWriter, session *Session) error
Save encrypts the session data and stores it as a cookie. The session values are serialized using gob encoding and then encrypted using AES-GCM before being base64 encoded and stored in the cookie.
type HandlerFunc ¶
HandlerFunc defines a handler function that receives an Context and returns an error. This allows for more elegant error handling compared to traditional http.HandlerFunc. If the handler returns an error, it will be passed to the configured error handler.
Example:
func getUserHandler(ctx Context) error {
id := ctx.Param("id")
user, err := getUserByID(id)
if err != nil {
return err // Error will be handled by error handler
}
return ctx.JSON(200, user)
}
func LoggingMiddleware ¶
func LoggingMiddleware(next HandlerFunc) HandlerFunc
LoggingMiddleware is a HandlerFunc-based middleware that logs HTTP requests with structured logging using slog. It works directly with the Context interface and maintains the elegant error handling pattern.
The logged information includes:
- name: "srv.Logging" (logger identifier)
- method: HTTP method (GET, POST, etc.)
- path: Request URL path
- user-agent: Client user agent string
- remote-addr: Client remote address
- duration: Request processing time
Note: This middleware cannot capture the exact status code since it works at the HandlerFunc level, but it provides comprehensive logging of request information.
Example:
mux.Middleware(srv.LoggingMiddleware)
func RecoverMiddleware ¶
func RecoverMiddleware(next HandlerFunc) HandlerFunc
RecoverMiddleware is a HandlerFunc-based middleware that recovers from panics during HTTP request processing. It works directly with the Context interface and maintains the elegant error handling pattern.
When a panic occurs, it logs the error using structured logging and converts the panic to an error that can be handled by the error handler.
The panic is logged with:
- name: "srv.Recover" (logger identifier)
- error: The recovered panic value
- path: Request URL path
- method: HTTP method
Example:
mux.Middleware(srv.RecoverMiddleware)
type HandlerFuncMiddleware ¶
type HandlerFuncMiddleware func(next HandlerFunc) HandlerFunc
HandlerFuncMiddleware represents middleware that works with HandlerFunc. It takes a HandlerFunc and returns a new HandlerFunc, allowing middleware to be chained while maintaining the srv package's error handling pattern. This enables middleware to work directly with the Context interface and maintain the elegant error handling approach.
Example:
func AuthMiddleware(next HandlerFunc) HandlerFunc {
return func(ctx Context) error {
token := ctx.GetHeader("Authorization")
if token == "" {
return erm.Unauthorized("missing authorization header", nil)
}
// Store authenticated user in context
ctx.Set("user", getUserFromToken(token))
return next(ctx) // Continue to next handler
}
}
func AddTrailingSlashMiddleware ¶
func AddTrailingSlashMiddleware(config TrailingSlashConfig) HandlerFuncMiddleware
AddTrailingSlashMiddleware returns a HandlerFunc-based middleware that adds a trailing slash to request URLs that don't already have one. It works directly with the Context interface and maintains the elegant error handling pattern.
The middleware can either redirect the client to the URL with trailing slash (when RedirectCode is set) or forward the request internally (when RedirectCode is 0).
Security: The middleware includes protection against open redirect vulnerabilities by sanitizing URLs that contain multiple slashes or backslashes.
Example usage:
// Default behavior (internal forward)
mux.Middleware(srv.AddTrailingSlashMiddleware(srv.DefaultTrailingSlashConfig))
// Redirect with 301 status code
config := srv.TrailingSlashConfig{RedirectCode: 301}
mux.Middleware(srv.AddTrailingSlashMiddleware(config))
func CORSMiddleware ¶
func CORSMiddleware(config CORSConfig) HandlerFuncMiddleware
CORSMiddleware returns a HandlerFunc-based CORS middleware that handles Cross-Origin Resource Sharing (CORS) according to the W3C specification. It supports both simple and preflight requests with comprehensive configuration options for security and compatibility.
Features:
- Origin validation with exact matching or wildcard support
- Preflight request handling for complex CORS scenarios
- Credential support with proper security constraints
- Custom expose headers for client access to response headers
- Configurable cache control via MaxAge for preflight responses
- Automatic Vary header management for proper caching behavior
- Security hardening against CORS misconfigurations
Security Considerations:
- When AllowCredentials is true and AllowOrigins contains "*", the middleware will echo the specific origin instead of using "*" to prevent security issues
- Origins are validated with exact string matching to prevent subdomain attacks
- Always adds appropriate Vary headers for proper cache behavior
Preflight Limitations: For proper CORS support with preflight requests, you need to register OPTIONS handlers for your routes, as HandlerFunc middleware can only process requests that match registered routes. For automatic preflight handling without explicit OPTIONS routes, consider using a different CORS solution.
Example usage:
// Basic configuration (allows all origins)
mux.Middleware(srv.CORSMiddleware(srv.DefaultCORSConfig))
// Production configuration with specific origins and credentials
corsConfig := srv.CORSConfig{
AllowOrigins: []string{"https://app.example.com", "https://admin.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Content-Type", "Authorization", "X-API-Key"},
AllowCredentials: true,
ExposeHeaders: []string{"X-Total-Count", "X-Rate-Limit"},
MaxAge: 3600, // Cache preflight for 1 hour
}
mux.Middleware(srv.CORSMiddleware(corsConfig))
// Remember to register OPTIONS handlers for preflight support
mux.Options("", "/api/users", func(ctx Context) error { return nil })
mux.Post("", "/api/users", createUser)
func SessionMiddleware ¶
func SessionMiddleware(store Store, sessionName string) HandlerFuncMiddleware
SessionMiddleware returns a HandlerFunc-based session middleware that automatically manages sessions for each request. It loads existing sessions from the store or creates new ones as needed, makes the session available through the Context, and automatically saves the session after the request completes.
The middleware integrates seamlessly with the srv package's Context interface, allowing easy session access via ctx.Get("session") or helper methods.
Example usage:
// Create session store
store := srv.NewInMemoryStore("myapp-session", srv.NewOptions())
// Add session middleware
mux.Middleware(srv.SessionMiddleware(store, "myapp-session"))
// Use in handlers
mux.Get("profile", "/profile", func(ctx srv.Context) error {
session := ctx.Get("session").(*srv.Session)
userID := session.Get("userID")
if userID == nil {
return ctx.Redirect(302, "/login")
}
return ctx.JSON(200, map[string]interface{}{"userID": userID})
})
type HttpContext ¶
type HttpContext struct {
// contains filtered or unexported fields
}
HttpContext provides a convenient wrapper around http.Request and http.ResponseWriter with additional functionality for storing request-scoped values, handling common HTTP operations, and providing helper methods for request/response processing.
HttpContext is thread-safe for concurrent access to its internal value store.
func NewHttpContext ¶
func NewHttpContext(w http.ResponseWriter, r *http.Request) *HttpContext
NewHttpContext creates a new HttpContext instance wrapping the provided http.ResponseWriter and http.Request. The context includes an empty thread-safe value store for request-scoped data.
func (*HttpContext) AddHeader ¶
func (c *HttpContext) AddHeader(key, value string)
AddHeader adds a response header. If a header with the same key already exists, the value will be appended.
func (*HttpContext) Cookie ¶
func (c *HttpContext) Cookie(key string) (*http.Cookie, error)
Cookie returns the named cookie provided in the request. Returns ErrNoCookie if no cookie with the given name is found.
func (*HttpContext) Cookies ¶
func (c *HttpContext) Cookies() []*http.Cookie
Cookies returns all cookies provided in the request.
func (*HttpContext) FormValue ¶
func (c *HttpContext) FormValue(key string) string
FormValue returns the value of the specified form parameter. It parses the form data if not already parsed.
func (*HttpContext) Get ¶
func (c *HttpContext) Get(key string) interface{}
Get retrieves a value from the context's value store by key. Returns nil if the key doesn't exist. This method is thread-safe and can be called concurrently.
func (*HttpContext) GetHeader ¶
func (c *HttpContext) GetHeader(key string) string
GetHeader returns the value of the specified request header.
func (*HttpContext) GetHeaders ¶
func (c *HttpContext) GetHeaders() http.Header
GetHeaders returns all request headers.
func (*HttpContext) HTML ¶
func (c *HttpContext) HTML(code int, html string) error
HTML writes an HTML response with the specified status code. The Content-Type header is automatically set to "text/html".
func (*HttpContext) HTMLBlob ¶
func (c *HttpContext) HTMLBlob(code int, blob []byte) error
HTMLBlob writes an HTML response with the specified status code. The Content-Type header is automatically set to "text/html".
func (*HttpContext) IsTLS ¶
func (c *HttpContext) IsTLS() bool
IsTLS returns true if the request was made over HTTPS/TLS.
func (*HttpContext) IsWebSocket ¶
func (c *HttpContext) IsWebSocket() bool
IsWebSocket returns true if this is a WebSocket upgrade request. It checks for the "Upgrade: websocket" header.
func (*HttpContext) JSON ¶
func (c *HttpContext) JSON(code int, v interface{}) error
JSON writes a JSON response with the specified status code. The Content-Type header is automatically set to "application/json". Returns an error if JSON encoding fails.
func (*HttpContext) Method ¶
func (c *HttpContext) Method() string
Method returns the HTTP method of the request (GET, POST, etc.).
func (*HttpContext) Param ¶
func (c *HttpContext) Param(key string) string
Param returns the value of the specified path parameter. This uses Go 1.22+ ServeMux path value extraction.
func (*HttpContext) Path ¶
func (c *HttpContext) Path() string
Path returns the URL path of the request.
func (*HttpContext) Query ¶
func (c *HttpContext) Query() url.Values
Query returns all URL query parameters as url.Values.
func (*HttpContext) QueryParam ¶
func (c *HttpContext) QueryParam(key string) string
QueryParam returns the value of the specified query parameter. Returns empty string if the parameter doesn't exist.
func (*HttpContext) Redirect ¶
func (c *HttpContext) Redirect(code int, url string) error
Redirect sends an HTTP redirect response with the specified status code and URL. Common status codes are 301 (permanent), 302 (found), 303 (see other), 307 (temporary), and 308 (permanent redirect).
func (*HttpContext) Request ¶
func (c *HttpContext) Request() *http.Request
Request returns the underlying http.Request object.
func (*HttpContext) Response ¶
func (c *HttpContext) Response() http.ResponseWriter
Response returns the underlying http.ResponseWriter object.
func (*HttpContext) Set ¶
func (c *HttpContext) Set(key string, value interface{})
Set stores a value in the context's value store with the given key. This method is thread-safe and can be called concurrently.
func (*HttpContext) SetCookie ¶
func (c *HttpContext) SetCookie(cookie *http.Cookie)
SetCookie adds a Set-Cookie header to the response.
func (*HttpContext) SetHeader ¶
func (c *HttpContext) SetHeader(key, value string)
SetHeader sets a response header. If a header with the same key already exists, it will be replaced.
func (*HttpContext) SetPath ¶
func (c *HttpContext) SetPath(path string)
SetPath sets the URL path of the request.
func (*HttpContext) String ¶
func (c *HttpContext) String(code int, text string) error
String writes a plain text response with the specified status code. The Content-Type header is automatically set to "text/plain".
func (*HttpContext) WriteHeader ¶
func (c *HttpContext) WriteHeader(code int)
WriteHeader sends an HTTP response header with the provided status code.
type InMemoryStore ¶
type InMemoryStore struct {
// contains filtered or unexported fields
}
InMemoryStore provides an in-memory session store implementation. It is thread-safe and suitable for development and single-instance deployments. For production with multiple instances, consider a distributed store.
func NewInMemoryStore ¶
func NewInMemoryStore(name string, options *Options) *InMemoryStore
NewInMemoryStore creates a new in-memory session store with the specified options. It automatically starts a cleanup routine to remove expired sessions.
func (*InMemoryStore) Close ¶
func (s *InMemoryStore) Close()
Close stops the cleanup routine and clears all sessions. This should be called when the store is no longer needed.
func (*InMemoryStore) Get ¶
Get retrieves an existing session or returns nil if not found or expired.
func (*InMemoryStore) Save ¶
func (s *InMemoryStore) Save(_ *http.Request, w http.ResponseWriter, session *Session) error
Save persists the session to the in-memory store and sets the session cookie.
type Mux ¶
type Mux struct {
// contains filtered or unexported fields
}
Mux provides a convenient wrapper around Go's standard http.ServeMux with helper methods for common HTTP operations, RESTful routing, URL reversing, and centralized error handling.
The Mux supports two types of handlers:
- Traditional http.Handler and http.HandlerFunc via Handle() and HandleFunc()
- Enhanced HandlerFunc via HTTP method helpers (Get, Post, etc.) with automatic error handling
- HandlerFunc middleware via the Middleware() method for chaining Context-aware middleware
func NewMux ¶
func NewMux() *Mux
NewMux creates a new Mux instance with an underlying http.ServeMux and a default error handler. The default error handler responds with a 500 Internal Server Error and logs the error. The returned Mux is safe for concurrent use by multiple goroutines.
func (*Mux) Delete ¶
func (m *Mux) Delete(name, pattern string, handler HandlerFunc)
Delete registers a named handler for DELETE requests to the specified pattern. If name is provided, the route can be used for URL generation via the Reverse method. If name is empty string, the route is registered without naming.
func (*Mux) ErrorHandler ¶
ErrorHandler sets a custom error handler for all HandlerFunc-based routes. The error handler will be called whenever a HandlerFunc returns a non-nil error. If no custom error handler is set, the default handler returns a 500 Internal Server Error.
Example:
mux.ErrorHandler(func(ctx Context, err error) {
log.Printf("Handler error: %v", err)
ctx.JSON(500, map[string]string{"error": err.Error()})
})
func (*Mux) Get ¶
func (m *Mux) Get(name, pattern string, handler HandlerFunc)
Get registers a named handler for GET requests to the specified pattern. If name is provided, the route can be used for URL generation via the Reverse method. If name is empty string, the route is registered without naming.
Example:
m.Get("user-list", "/users", handler) // Named route
m.Get("", "/health", handler) // Unnamed route
url, err := m.Reverse("user-list", nil) // Generate: "/users"
func (*Mux) HandleFunc ¶
func (m *Mux) HandleFunc(pattern string, handler http.HandlerFunc)
HandleFunc registers a handler function for the given pattern.
func (*Mux) Head ¶
func (m *Mux) Head(name, pattern string, handler HandlerFunc)
Head registers a named handler for HEAD requests to the specified pattern. If name is provided, the route can be used for URL generation via the Reverse method. If name is empty string, the route is registered without naming.
func (*Mux) Middleware ¶
func (m *Mux) Middleware(middleware HandlerFuncMiddleware)
Middleware adds HandlerFunc-based middleware to the Mux. Middleware will be applied to all routes registered after this method is called. Middleware are applied in the order they are added (first added = outermost wrapper).
The middleware function receives the next HandlerFunc in the chain and returns a new HandlerFunc that typically calls the next function with additional logic before, after, or around the call. This allows middleware to work directly with the Context interface and maintain the elegant error handling pattern.
Example:
// Add authentication middleware
mux.Middleware(func(next HandlerFunc) HandlerFunc {
return func(ctx Context) error {
token := ctx.GetHeader("Authorization")
if token == "" {
return erm.Unauthorized("missing authorization header", nil)
}
// Continue to next handler
return next(ctx)
}
})
// Add timing middleware
mux.Middleware(func(next HandlerFunc) HandlerFunc {
return func(ctx Context) error {
start := time.Now()
err := next(ctx)
duration := time.Since(start)
log.Printf("Request took %v", duration)
return err
}
})
func (*Mux) Mux ¶
Mux returns the underlying http.ServeMux for advanced usage or integration with other HTTP libraries.
func (*Mux) Options ¶
func (m *Mux) Options(name, pattern string, handler HandlerFunc)
Options registers a named handler for OPTIONS requests to the specified pattern. If name is provided, the route can be used for URL generation via the Reverse method. If name is empty string, the route is registered without naming.
func (*Mux) Patch ¶
func (m *Mux) Patch(name, pattern string, handler HandlerFunc)
Patch registers a named handler for PATCH requests to the specified pattern. If name is provided, the route can be used for URL generation via the Reverse method. If name is empty string, the route is registered without naming.
func (*Mux) Post ¶
func (m *Mux) Post(name, pattern string, handler HandlerFunc)
Post registers a named handler for POST requests to the specified pattern. If name is provided, the route can be used for URL generation via the Reverse method. If name is empty string, the route is registered without naming.
func (*Mux) Put ¶
func (m *Mux) Put(name, pattern string, handler HandlerFunc)
Put registers a named handler for PUT requests to the specified pattern. If name is provided, the route can be used for URL generation via the Reverse method. If name is empty string, the route is registered without naming.
func (*Mux) Reverse ¶
Reverse generates a URL for the named route with the provided parameters. Parameters should be provided as a map where keys match the path parameter names in the route pattern (e.g., "id" for "/users/{id}").
Multiple HTTP methods can share the same route name if they have the same pattern, enabling RESTful route naming (e.g., "users" for both GET /users and POST /users).
Parameters:
- name: The route name specified when registering the route
- params: Map of parameter names to values for substitution
Returns the generated URL path and any error encountered. Errors are returned as erm.Error instances: erm.NotFound for unknown routes and erm.RequiredError for missing required parameters.
Example:
m.Get("user-profile", "/users/{id}", handler)
m.Post("users", "/users", handler)
// Generate URLs
profileURL, err := m.Reverse("user-profile", map[string]string{"id": "123"})
// Returns: "/users/123"
usersURL, err := m.Reverse("users", nil)
// Returns: "/users"
// Error handling
_, err := m.Reverse("non-existent", nil)
// Returns: erm.NotFound error with 404 status
_, err := m.Reverse("user-profile", nil)
// Returns: erm.RequiredError for missing {id} parameter
type Options ¶
type Options struct {
// Path sets the cookie path. Defaults to "/".
Path string
// Domain sets the cookie domain.
Domain string
// MaxAge sets the maximum age for the session in seconds.
// If <= 0, the session cookie will be deleted when the browser closes.
MaxAge int
// Secure indicates whether the cookie should only be sent over HTTPS.
Secure bool
// HttpOnly indicates whether the cookie should be accessible only through HTTP requests.
// This prevents access via JavaScript, mitigating XSS attacks.
HttpOnly bool
// SameSite controls when cookies are sent with cross-site requests.
SameSite http.SameSite
}
Options holds configuration for session cookies.
type Route ¶
type Route struct {
Name string // The route name for URL reversing
Pattern string // URL pattern (e.g., "/users/{id}")
}
Route represents a named route with its URL pattern. Multiple HTTP methods can share the same route if they have the same pattern. This is used internally for URL reversing functionality.
type Session ¶
type Session struct {
// The ID of the session, generated by stores. It should not be used for
// user data.
ID string
// Values contains the user-data for the session.
Values url.Values
Options *Options
IsNew bool
// contains filtered or unexported fields
}
Session represents a user session with associated data and configuration. It provides a secure way to maintain state across HTTP requests.
type Store ¶
type Store interface {
// Get should return a cached session.
Get(r *http.Request, name string) (*Session, error)
// New should create and return a new session.
//
// Note that New should never return a nil session, even in the case of
// an error if using the Registry infrastructure to cache the session.
New(r *http.Request, name string) (*Session, error)
// Save should persist session to the underlying store implementation.
Save(r *http.Request, w http.ResponseWriter, s *Session) error
}
Store defines the interface for session storage backends. Implementations must be thread-safe.
type TrailingSlashConfig ¶
type TrailingSlashConfig struct {
// RedirectCode is the HTTP status code used when redirecting the request.
// If set to 0, the request is forwarded internally without a redirect.
// If set to a redirect code (e.g., 301, 302), an HTTP redirect is performed.
//
// Optional. Default value 0 (forward internally).
RedirectCode int
}
TrailingSlashConfig defines the configuration for AddTrailingSlash middleware.