Add production-ready HTTP server package with routing, health checks, and middleware
Introduces server/ sub-package as the server-side companion to the existing Client. Includes Router (over http.ServeMux with groups and mounting), graceful shutdown with signal handling, health endpoints (/healthz, /readyz), and built-in middlewares (RequestID, Recovery, Logging). Zero external dependencies. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
89
server/options.go
Normal file
89
server/options.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"time"
|
||||
)
|
||||
|
||||
type serverOptions struct {
|
||||
addr string
|
||||
readTimeout time.Duration
|
||||
readHeaderTimeout time.Duration
|
||||
writeTimeout time.Duration
|
||||
idleTimeout time.Duration
|
||||
shutdownTimeout time.Duration
|
||||
logger *slog.Logger
|
||||
middlewares []Middleware
|
||||
onShutdown []func()
|
||||
}
|
||||
|
||||
// Option configures a Server.
|
||||
type Option func(*serverOptions)
|
||||
|
||||
// WithAddr sets the listen address. Default is ":8080".
|
||||
func WithAddr(addr string) Option {
|
||||
return func(o *serverOptions) { o.addr = addr }
|
||||
}
|
||||
|
||||
// WithReadTimeout sets the maximum duration for reading the entire request.
|
||||
func WithReadTimeout(d time.Duration) Option {
|
||||
return func(o *serverOptions) { o.readTimeout = d }
|
||||
}
|
||||
|
||||
// WithReadHeaderTimeout sets the maximum duration for reading request headers.
|
||||
func WithReadHeaderTimeout(d time.Duration) Option {
|
||||
return func(o *serverOptions) { o.readHeaderTimeout = d }
|
||||
}
|
||||
|
||||
// WithWriteTimeout sets the maximum duration before timing out writes of the response.
|
||||
func WithWriteTimeout(d time.Duration) Option {
|
||||
return func(o *serverOptions) { o.writeTimeout = d }
|
||||
}
|
||||
|
||||
// WithIdleTimeout sets the maximum amount of time to wait for the next request
|
||||
// when keep-alives are enabled.
|
||||
func WithIdleTimeout(d time.Duration) Option {
|
||||
return func(o *serverOptions) { o.idleTimeout = d }
|
||||
}
|
||||
|
||||
// WithShutdownTimeout sets the maximum duration to wait for active connections
|
||||
// to close during graceful shutdown. Default is 15 seconds.
|
||||
func WithShutdownTimeout(d time.Duration) Option {
|
||||
return func(o *serverOptions) { o.shutdownTimeout = d }
|
||||
}
|
||||
|
||||
// WithLogger sets the structured logger used by the server for lifecycle events.
|
||||
func WithLogger(l *slog.Logger) Option {
|
||||
return func(o *serverOptions) { o.logger = l }
|
||||
}
|
||||
|
||||
// WithMiddleware appends server middlewares to the chain.
|
||||
// These are applied to the handler in the order given.
|
||||
func WithMiddleware(mws ...Middleware) Option {
|
||||
return func(o *serverOptions) { o.middlewares = append(o.middlewares, mws...) }
|
||||
}
|
||||
|
||||
// WithOnShutdown registers a function to be called during graceful shutdown,
|
||||
// before the HTTP server begins draining connections.
|
||||
func WithOnShutdown(fn func()) Option {
|
||||
return func(o *serverOptions) { o.onShutdown = append(o.onShutdown, fn) }
|
||||
}
|
||||
|
||||
// Defaults returns a production-ready set of options including standard
|
||||
// middleware (RequestID, Recovery, Logging), sensible timeouts, and the
|
||||
// provided logger.
|
||||
//
|
||||
// Middleware order: RequestID → Recovery → Logging → user handler.
|
||||
func Defaults(logger *slog.Logger) []Option {
|
||||
return []Option{
|
||||
WithReadHeaderTimeout(10 * time.Second),
|
||||
WithIdleTimeout(120 * time.Second),
|
||||
WithShutdownTimeout(15 * time.Second),
|
||||
WithLogger(logger),
|
||||
WithMiddleware(
|
||||
RequestID(),
|
||||
Recovery(WithRecoveryLogger(logger)),
|
||||
Logging(logger),
|
||||
),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user