Documentation
¶
Overview ¶
Package servekit provides a small, net/http-first bootstrap layer for HTTP services.
The package focuses on production defaults for server lifecycle, middleware wiring, health/readiness probes, request and correlation IDs, JSON encoding, panic logging, graceful shutdown, and opt-in CORS.
When OpenTelemetry is enabled, Servekit also wires request tracing and request metrics into the default handler stack. On the built-in Run path it additionally wires server-level connection metrics, because those depend on http.Server.ConnState rather than only on request middleware.
Servekit is intentionally not a web framework: it does not define routing syntax beyond http.ServeMux patterns, does not impose dependency injection, and does not hide net/http primitives.
Typical usage is to construct a Server with New, register handlers with Handle or HandleHTTP, then call Run from your main package.
Index ¶
- func Chain(h http.Handler, middlewares ...Middleware) http.Handler
- func CorrelationIDFromContext(ctx context.Context) string
- func Error(status int, message string, err error) error
- func RequestIDFromContext(ctx context.Context) string
- func SpanIDFromContext(ctx context.Context) string
- func TraceIDFromContext(ctx context.Context) string
- type CORSConfig
- type EndpointOption
- func WithAuthCheck(check func(*http.Request) bool) EndpointOption
- func WithAuthGate(fn func(*http.Request) error) EndpointOption
- func WithBodyLimit(n int64) EndpointOption
- func WithEndpointMiddleware(mw ...Middleware) EndpointOption
- func WithEndpointResponseEncoder(encoder ResponseEncoder) EndpointOption
- func WithEndpointTimeout(timeout time.Duration) EndpointOption
- func WithSkipAccessLog() EndpointOption
- func WithSkipTelemetry() EndpointOption
- type ErrorEncoder
- type HTTPError
- type HandlerFunc
- type Middleware
- type Option
- func WithAccessLogEnabled(enabled bool) Option
- func WithAddr(addr string) Option
- func WithBuildInfo(version, commit, date string) Option
- func WithCORSConfig(cfg CORSConfig) Option
- func WithCorrelationIDEnabled(enabled bool) Option
- func WithDefaultEndpointsEnabled(enabled bool) Option
- func WithErrorEncoder(encoder ErrorEncoder) Option
- func WithHTTPServerErrorLog(logger *log.Logger) Option
- func WithHTTPServerErrorLogLevel(level slog.Level) Option
- func WithHealthHandler(handler http.Handler) Option
- func WithIdleTimeout(timeout time.Duration) Option
- func WithLogger(logger *slog.Logger) Option
- func WithMaxHeaderBytes(n int) Option
- func WithMeterProvider(mp metric.MeterProvider) Option
- func WithMiddleware(mw ...Middleware) Option
- func WithMux(mux *http.ServeMux) Option
- func WithOTelAttributes(fn func(*http.Request) []attribute.KeyValue) Option
- func WithOTelPanicMetricEnabled(enabled bool) Option
- func WithOpenTelemetryEnabled(enabled bool) Option
- func WithPanicPropagation(enabled bool) Option
- func WithPropagator(p propagation.TextMapPropagator) Option
- func WithReadHeaderTimeout(timeout time.Duration) Option
- func WithReadTimeout(timeout time.Duration) Option
- func WithReadinessChecks(checks ...ReadinessCheck) Option
- func WithRecoveryEnabled(enabled bool) Option
- func WithRequestBodyLimit(n int64) Option
- func WithRequestIDEnabled(enabled bool) Option
- func WithResponseEncoder(encoder ResponseEncoder) Option
- func WithRouteLabeler(fn func(*http.Request) string) Option
- func WithShutdownDrainDelay(delay time.Duration) Option
- func WithShutdownTimeout(timeout time.Duration) Option
- func WithSpanNameFormatter(fn func(*http.Request, string) string) Option
- func WithTracerProvider(tp trace.TracerProvider) Option
- func WithWriteTimeout(timeout time.Duration) Option
- type ReadinessCheck
- type ResponseEncoder
- type Server
- func (s *Server) Handle(method, path string, h HandlerFunc, opts ...EndpointOption)
- func (s *Server) HandleHTTP(method, path string, h http.Handler, opts ...EndpointOption)
- func (s *Server) Handler() http.Handler
- func (s *Server) Ready() bool
- func (s *Server) Run(ctx context.Context) error
- func (s *Server) SetReady(ready bool)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Chain ¶
func Chain(h http.Handler, middlewares ...Middleware) http.Handler
Chain applies middlewares around h in declaration order.
For Chain(h, a, b), requests flow as a -> b -> h.
func CorrelationIDFromContext ¶
CorrelationIDFromContext returns the correlation ID inserted by CorrelationID.
func RequestIDFromContext ¶
RequestIDFromContext returns the request ID inserted by RequestID.
func SpanIDFromContext ¶
SpanIDFromContext returns the active span ID for the request context.
func TraceIDFromContext ¶
TraceIDFromContext returns the active trace ID for the request context.
Types ¶
type CORSConfig ¶
type CORSConfig struct {
// AllowedOrigins is the exact origin allowlist in scheme://host[:port] form.
// When empty and credentials are disabled, Servekit allows all origins.
AllowedOrigins []string
// AllowedMethods is the allowlist returned on successful preflight responses.
// When empty, Servekit uses a conservative default set of common HTTP methods.
AllowedMethods []string
// AllowedHeaders is the allowlist for Access-Control-Request-Headers on
// preflight requests. When empty, Servekit uses a small default set.
AllowedHeaders []string
// ExposedHeaders is the list of response headers browsers may expose to
// calling JavaScript on successful cross-origin requests.
ExposedHeaders []string
// AllowCredentials enables Access-Control-Allow-Credentials: true on
// successful CORS responses. When true, AllowedOrigins must be explicit and
// must not contain "*".
AllowCredentials bool
// MaxAge controls Access-Control-Max-Age on successful preflight responses.
// A value of 0 uses Servekit's default of 600 seconds. A positive value uses
// the provided number of seconds. A negative value disables the header.
MaxAge int
}
CORSConfig configures Servekit's opt-in CORS middleware.
AllowedOrigins is a list of exact origins in scheme://host[:port] form. When AllowCredentials is true, AllowedOrigins must be provided explicitly and must not contain "*", because credentialed CORS responses cannot allow all origins with a wildcard.
type EndpointOption ¶
type EndpointOption func(*endpointConfig)
EndpointOption configures per-endpoint behavior for Handle and HandleHTTP.
func WithAuthCheck ¶
func WithAuthCheck(check func(*http.Request) bool) EndpointOption
WithAuthCheck installs an authorization gate for the endpoint.
When check returns false, Handle and HandleHTTP respond with HTTP 401 via the current ErrorEncoder and do not invoke the handler. This convenience form always returns HTTP 401. Use WithAuthGate when you need control over the returned status or message.
func WithAuthGate ¶
func WithAuthGate(fn func(*http.Request) error) EndpointOption
WithAuthGate installs an error-returning auth gate for the endpoint.
When fn returns a non-nil error, Handle and HandleHTTP pass that error directly to the current ErrorEncoder and do not invoke the handler. Return HTTPError values or Error(...) when you need explicit control over the response status and message.
func WithBodyLimit ¶
func WithBodyLimit(n int64) EndpointOption
WithBodyLimit sets the maximum number of bytes Servekit will read from the request body for this endpoint. A value of -1 disables the limit entirely. The default is the server-wide WithRequestBodyLimit value (4 MiB unless overridden).
When the limit is exceeded, net/http returns an *http.MaxBytesError and Servekit maps it to HTTP 413 Request Entity Too Large.
func WithEndpointMiddleware ¶
func WithEndpointMiddleware(mw ...Middleware) EndpointOption
WithEndpointMiddleware appends middleware applied only to that endpoint.
Endpoint middleware wraps the handler before global server middleware is applied by Server.Handler.
func WithEndpointResponseEncoder ¶
func WithEndpointResponseEncoder(encoder ResponseEncoder) EndpointOption
WithEndpointResponseEncoder overrides success encoding for one endpoint.
This option applies only to Handle. If the encoder returns an error, that error is delegated to the server ErrorEncoder.
func WithEndpointTimeout ¶
func WithEndpointTimeout(timeout time.Duration) EndpointOption
WithEndpointTimeout sets a per-endpoint context timeout.
A timeout of zero leaves the incoming request context unchanged.
func WithSkipAccessLog ¶
func WithSkipAccessLog() EndpointOption
WithSkipAccessLog suppresses AccessLog output for one endpoint.
This is useful for high-frequency probes such as /healthz and /readyz.
func WithSkipTelemetry ¶
func WithSkipTelemetry() EndpointOption
WithSkipTelemetry suppresses built-in OTel tracing and metrics for one endpoint.
type ErrorEncoder ¶
ErrorEncoder writes error responses for Handle.
The returned error is ignored by Servekit, so implementations should treat best-effort response writes as terminal. If the response has already been committed by an earlier writer, an ErrorEncoder may not be able to change the status code or replace the response body.
func JSONError ¶
func JSONError() ErrorEncoder
JSONError returns the default error encoder for Handle.
JSONError maps HTTPError values to their StatusCode, maps context cancellation and deadline errors to HTTP 504, and otherwise returns HTTP 500. The payload shape is {"error": "..."} and includes request_id when one is present in the request context.
type HTTPError ¶
type HTTPError struct {
StatusCode int // StatusCode is the HTTP status returned for this error.
Message string // Message is the client-facing error text.
Err error // Err is the wrapped underlying cause, when present.
}
HTTPError carries an HTTP status code alongside an underlying error.
Use HTTPError (or Error) when handlers need explicit control over status mapping instead of relying on the default 500/504 behavior.
type HandlerFunc ¶
HandlerFunc is the function form accepted by Server.Handle.
The request passed to HandlerFunc carries any endpoint timeout set with WithEndpointTimeout in r.Context(). Returning a non-nil error delegates response writing to the server ErrorEncoder.
type Middleware ¶
Middleware wraps an http.Handler and returns a new handler.
func AccessLog ¶
func AccessLog(logger *slog.Logger) Middleware
AccessLog logs one structured entry per completed request.
The remote_addr field reflects the direct TCP peer address from http.Request.RemoteAddr. Trusting proxy headers is the responsibility of upstream middleware, not Servekit's access logger.
func CorrelationID ¶
func CorrelationID() Middleware
CorrelationID ensures each request has an X-Correlation-ID value.
func Recovery ¶
func Recovery(logger *slog.Logger, propagate bool) Middleware
Recovery logs panics and then applies one of two mutually exclusive strategies.
By default, with propagate set to false, Recovery uses contain-and-continue behavior: it logs the original panic value and stack trace, writes a best-effort JSON 500 in Servekit's default error shape when the response is still uncommitted, and then returns normally. When a request ID is already available, Recovery includes it in that fallback body. This keeps panic handling at the HTTP layer for ordinary request/response handlers.
When propagate is true, Recovery switches to transport-abort propagation: it still logs the original panic value and stack trace, but it does not write a fallback response and instead re-panics with http.ErrAbortHandler. That mode is useful when a team wants net/http abort semantics, such as for streaming or proxy-style handlers, without also getting the standard library's own panic stack-trace logging at the server boundary.
func RequestID ¶
func RequestID() Middleware
RequestID ensures each request has an X-Request-ID value.
func SkipAccessLog ¶
func SkipAccessLog() Middleware
SkipAccessLog marks a request so AccessLog omits its log entry.
type Option ¶
type Option func(*Server)
Option mutates server configuration during New.
func WithAccessLogEnabled ¶
WithAccessLogEnabled enables or disables request access logging middleware.
func WithBuildInfo ¶
WithBuildInfo overrides the version, commit, and date fields served by the built-in /version endpoint.
func WithCORSConfig ¶
func WithCORSConfig(cfg CORSConfig) Option
WithCORSConfig opts into Servekit's built-in CORS middleware. CORS is disabled by default.
AllowedOrigins is origin-based (scheme + host + port), not domain-based. Host or domain allowlisting is intentionally out of scope for Servekit and belongs at the ingress or reverse-proxy layer.
Servekit validates the config when Handler constructs the middleware. Invalid AllowCredentials and AllowedOrigins combinations panic with a servekit-prefixed message.
func WithCorrelationIDEnabled ¶
WithCorrelationIDEnabled enables or disables correlation ID middleware.
func WithDefaultEndpointsEnabled ¶
WithDefaultEndpointsEnabled enables or disables built-in /livez, /readyz, and /version endpoints, plus /healthz when WithHealthHandler is supplied.
func WithErrorEncoder ¶
func WithErrorEncoder(encoder ErrorEncoder) Option
WithErrorEncoder sets the default error encoder used by Handle.
A nil encoder is ignored.
func WithHTTPServerErrorLog ¶
WithHTTPServerErrorLog sets the stdlib logger used for http.Server.ErrorLog.
This is an advanced override for users who want full control over the server's internal transport and accept-loop logging. When unset, Run derives ErrorLog from the server slog logger's handler and the configured WithHTTPServerErrorLogLevel value. When this option is set, it takes precedence and WithHTTPServerErrorLogLevel is ignored.
func WithHTTPServerErrorLogLevel ¶
WithHTTPServerErrorLogLevel sets the emitted slog level used when Run derives http.Server.ErrorLog from the server slog logger's handler.
This option is ignored when WithHTTPServerErrorLog supplies an explicit stdlib logger. It controls the severity label attached to derived ErrorLog records. It does not change the slog handler's own enabled threshold.
func WithHealthHandler ¶
WithHealthHandler mounts a user-defined health endpoint at /healthz.
Servekit does not impose built-in health semantics beyond /livez and /readyz. Use this hook when your service wants a broader or richer health endpoint without replacing the default operational routes.
func WithIdleTimeout ¶
WithIdleTimeout sets http.Server.IdleTimeout.
func WithLogger ¶
WithLogger sets the logger used by built-in middleware and server internals.
When WithHTTPServerErrorLog is not supplied, Run also derives http.Server's ErrorLog from this logger's handler. That derived logger reuses the handler's output, formatting, and attributes, but the emitted record level comes from WithHTTPServerErrorLogLevel rather than from the handler's own threshold.
A nil logger is ignored and leaves the current logger unchanged.
func WithMaxHeaderBytes ¶
WithMaxHeaderBytes sets http.Server.MaxHeaderBytes when n is greater than zero.
func WithMeterProvider ¶
func WithMeterProvider(mp metric.MeterProvider) Option
WithMeterProvider sets the meter provider used by OTel middleware.
When nil, Servekit uses otel.GetMeterProvider().
func WithMiddleware ¶
func WithMiddleware(mw ...Middleware) Option
WithMiddleware appends global middleware to the server handler stack.
func WithMux ¶
WithMux replaces the underlying http.ServeMux used for route registration.
A nil mux is ignored. This is an advanced escape hatch for integration with an existing mux. Most users should let Servekit manage its own mux.
func WithOTelAttributes ¶
WithOTelAttributes appends request attributes to spans and metrics.
func WithOTelPanicMetricEnabled ¶
WithOTelPanicMetricEnabled enables or disables panic counter metrics.
func WithOpenTelemetryEnabled ¶
WithOpenTelemetryEnabled toggles Servekit's built-in OTel middleware.
func WithPanicPropagation ¶
WithPanicPropagation switches Recovery between contain-and-continue mode and transport-abort propagation mode.
This option only has an effect when recovery middleware is enabled.
The default is false. In that mode recovered requests do not re-panic: Recovery logs the original panic value and stack trace, writes a best-effort JSON 500 when the response is still uncommitted, and then returns normally.
When enabled is true, Recovery switches to the mutually exclusive propagate mode. In that mode it still logs the original panic value and stack trace, but it never writes a fallback status code or body and instead re-panics with http.ErrAbortHandler. Teams typically choose this mode when they want connection-abort semantics from net/http, such as preserving streaming or proxy behavior, while still suppressing the standard library's own panic stack-trace logging at the server boundary.
func WithPropagator ¶
func WithPropagator(p propagation.TextMapPropagator) Option
WithPropagator sets the text map propagator used to extract incoming context.
When nil, Servekit uses otel.GetTextMapPropagator().
func WithReadHeaderTimeout ¶
WithReadHeaderTimeout sets http.Server.ReadHeaderTimeout.
func WithReadTimeout ¶
WithReadTimeout sets http.Server.ReadTimeout.
func WithReadinessChecks ¶
func WithReadinessChecks(checks ...ReadinessCheck) Option
WithReadinessChecks appends checks evaluated by the built-in /readyz endpoint.
func WithRecoveryEnabled ¶
WithRecoveryEnabled enables or disables Servekit's panic recovery middleware.
The default is true.
When enabled, Servekit installs Recovery around the handler stack. With the default WithPanicPropagation(false), recovered requests do not re-panic: Recovery logs the original panic value and stack trace, writes a best-effort JSON 500 when the response is still uncommitted, and then returns normally.
WithPanicPropagation(true) changes only that recovery behavior. In that mode Recovery still logs the original panic, but it does not attempt a fallback response and instead re-panics with http.ErrAbortHandler so net/http aborts the request.
When enabled is false, Servekit does not install the outer Recovery middleware. Panics still escape to the surrounding net/http server or test harness, although inner observability middleware may briefly recover and re-panic so they can record logs, spans, or metrics.
func WithRequestBodyLimit ¶
WithRequestBodyLimit sets the default maximum request body size in bytes for all endpoints. Individual endpoints can override this with WithBodyLimit. Set to -1 to disable the limit globally.
The default is 4 MiB. This limit is enforced via http.MaxBytesReader, which causes reads beyond the limit to return *http.MaxBytesError, mapped to HTTP 413.
func WithRequestIDEnabled ¶
WithRequestIDEnabled enables or disables request ID middleware.
func WithResponseEncoder ¶
func WithResponseEncoder(encoder ResponseEncoder) Option
WithResponseEncoder sets the default success response encoder for Handle.
A nil encoder is ignored.
func WithRouteLabeler ¶
WithRouteLabeler overrides the low-cardinality route label strategy.
func WithShutdownDrainDelay ¶
WithShutdownDrainDelay waits after becoming unready before shutdown begins.
func WithShutdownTimeout ¶
WithShutdownTimeout sets the timeout used for graceful shutdown.
func WithSpanNameFormatter ¶
WithSpanNameFormatter overrides per-request span naming.
func WithTracerProvider ¶
func WithTracerProvider(tp trace.TracerProvider) Option
WithTracerProvider sets the tracer provider used by OTel middleware.
When nil, Servekit uses otel.GetTracerProvider().
func WithWriteTimeout ¶
WithWriteTimeout sets http.Server.WriteTimeout.
For streaming, SSE, reverse proxying, and other long-lived responses, you will often want to override the default and use zero or another value that matches the endpoint behavior.
type ReadinessCheck ¶
ReadinessCheck is invoked by the built-in /readyz endpoint.
Returning nil marks the dependency healthy. Returning an error marks the service not ready and includes the error text in the response payload.
type ResponseEncoder ¶
ResponseEncoder writes successful responses for Handle.
Returning an error passes control to the server ErrorEncoder. Implementations should avoid committing a success status or body before returning an error whenever practical. Once a success response has been committed, the ErrorEncoder may no longer be able to replace it with an error response.
func JSONResponse ¶
func JSONResponse() ResponseEncoder
JSONResponse returns the default success encoder for Handle.
A nil payload writes HTTP 204 No Content with no body. A non-nil payload writes HTTP 200 with Content-Type application/json and body shape {"data": <payload>}. JSONResponse writes directly to the ResponseWriter using normal net/http response semantics. If JSON encoding fails after the success status has been committed, Handle will still call the server ErrorEncoder, but the error response may not be able to replace the already-committed success status.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server bootstraps an HTTP service with production-oriented defaults.
Server keeps net/http as the execution model while providing explicit hooks for middleware, probe checks, encoding, and lifecycle tuning via Option.
func New ¶
New constructs a Server with defaults and applies opts in order.
Defaults include JSON response/error encoders, middleware for panic logging, OpenTelemetry, request IDs, correlation IDs, and access logs, built-in /livez, /readyz, and /version endpoints, plus conservative http.Server timeout values.
A newly constructed Server starts not ready. By default Run marks readiness true once serving starts, unless the application has already opted into explicit readiness control via SetReady. Applications that use Handler with an external http.Server lifecycle should call SetReady(true) only once they are actually ready to receive traffic.
func (*Server) Handle ¶
func (s *Server) Handle(method, path string, h HandlerFunc, opts ...EndpointOption)
Handle registers a method/path endpoint backed by a HandlerFunc.
Handle applies endpoint options in this order: timeout and auth gate before invoking h with an updated request context, then success encoding with the server ResponseEncoder unless WithEndpointResponseEncoder overrides it. Errors from h or the encoder are sent through the server ErrorEncoder. If a success response has already been committed, the error path may not be able to replace it cleanly.
func (*Server) HandleHTTP ¶
func (s *Server) HandleHTTP(method, path string, h http.Handler, opts ...EndpointOption)
HandleHTTP registers a method/path endpoint backed by a raw http.Handler.
HandleHTTP applies endpoint options in this order: timeout and auth gate before invoking h, then endpoint middleware. Use HandleHTTP when you need direct control over response writing while still using Servekit middleware composition and endpoint options.
Optional writer capabilities such as Flush and Hijack are not guaranteed by http.ResponseWriter itself. They depend on what the underlying concrete writer supports at runtime. Servekit preserves those capabilities when they are present so HandleHTTP remains a credible raw escape hatch for streaming, upgrade, proxy, and other raw-response use cases.
func (*Server) Handler ¶
Handler builds the server's root http.Handler.
It wraps the server mux with any enabled built-in middleware and any middleware added via WithMiddleware. Request flow is: CORS (when configured), panic logging (when enabled), OpenTelemetry (when enabled), request ID (when enabled), correlation ID (when enabled), access log (when enabled), custom middleware, then the mux.
func (*Server) Run ¶
Run starts serving and blocks until shutdown completes or serving fails.
Run listens on WithAddr (default :8080), delegates request serving to net/http.Server, marks readiness true once serving starts unless readiness has already been set explicitly, and initiates graceful shutdown when ctx is canceled or SIGINT/SIGTERM is received. During shutdown readiness is set false, optional drain delay is applied, then http.Server.Shutdown runs with WithShutdownTimeout.
Run marks the server ready immediately once the listener is accepting connections, before any application-level warmup. If your service requires explicit warmup before receiving traffic, call SetReady(false) after New() and SetReady(true) only once warmup is complete. Run will not override a readiness state that was set explicitly.
The exact transport and protocol capabilities visible to handlers come from the underlying net/http server configuration used for the active run path. Servekit's own wrappers preserve optional ResponseWriter capabilities that are already present. They do not invent new ones.
Run also configures http.Server.ErrorLog. By default Servekit adapts the server slog handler into the stdlib *log.Logger shape that net/http expects. Users can override that logger explicitly with WithHTTPServerErrorLog.
Run returns wrapped listen/shutdown errors or the serve loop error.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
advanced-composition
command
|
|
|
basic
command
|
|
|
cors
command
|
|
|
custom-encoding
command
|
|
|
endpoint-controls
command
|
|
|
external-server
command
|
|
|
logging
command
|
|
|
readiness
command
|
|
|
response-capture
command
|
|
|
reverse-proxy
command
|
|
|
streaming
command
|
|
|
telemetry
command
|
|
|
Package version exposes immutable build metadata for a running service.
|
Package version exposes immutable build metadata for a running service. |