servekit

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Apr 12, 2026 License: MIT Imports: 30 Imported by: 0

README

Servekit

Release CI Go Support License

Overview

Servekit is a small Go package for bootstrapping HTTP services on top of net/http. It gives a service a real operational baseline from the first constructor call: probes, JSON response handling, request and correlation IDs, access logs, panic recovery, graceful shutdown, opt-in CORS, and built-in OpenTelemetry tracing and metrics.

It is especially useful for APIs and microservices that want consistent HTTP bootstrap without adopting a full web framework.

Servekit is not a framework. You still work with http.Request, http.Handler, and http.ServeMux. The point is to stop rebuilding the same service bootstrap around them.

It also does not lock you into only the built-in stack. Services can add their own global middleware with WithMiddleware(...) and route-local middleware with WithEndpointMiddleware(...) while staying on the normal Servekit path.

Why Servekit exists

Many Go services spend a meaningful amount of code on the same HTTP setup work: configuring http.Server, wiring middleware, handling panics, exposing probes, publishing build information, and shutting down cleanly.

That work matters, but it usually gets rewritten service by service and drifts a little each time. Servekit pulls it into a small, net/http-first package so new services can start from one coherent baseline and spend more code on domain behavior.

Its goal is narrow: own the reusable HTTP bootstrap layer, not the whole application.

What Servekit is not

Servekit is not a web framework. It does not replace net/http, add its own router DSL, or impose a different application model.

It also does not try to own dependency injection, background work, config loading, or service discovery. Those concerns stay with the application.

It is not a full observability platform either. Servekit gives the HTTP layer a strong default baseline, but the application still owns its telemetry backend, dashboards, alerting, and broader operational policy.

Good fit / not a fit

Servekit is a good fit when:

  • you want to stay on net/http but stop rebuilding the same service bootstrap around it
  • you want built-in probes, readiness, request IDs, access logging, panic recovery, OpenTelemetry, and graceful shutdown from the start
  • you want strong defaults without giving up application-owned middleware
  • you want one package that can cover both ordinary request/response routes and raw http.Handler endpoints such as streaming, proxying, and upgrades

Servekit is probably not a fit when:

  • you want a batteries-included web framework or a non-stdlib routing model
  • your service already has a settled bootstrap stack and Servekit would just duplicate it
  • you mainly want a full framework abstraction rather than a net/http-first bootstrap layer

Installation

go get github.com/jaredjakacky/servekit
import servekit "github.com/jaredjakacky/servekit"

Quick Start

package main

import (
	"context"
	"log"
	"net/http"

	servekit "github.com/jaredjakacky/servekit"
)

func main() {
	s := servekit.New()

	s.Handle(http.MethodGet, "/coffee", func(r *http.Request) (any, error) {
		return map[string]string{
			"drink":  "coffee",
			"status": "ready",
		}, nil
	})

	if err := s.Run(context.Background()); err != nil {
		log.Fatal(err)
	}
}

Run() starts the server on the configured address, which defaults to :8080, marks it ready once it begins serving, and handles shutdown on cancellation or SIGINT / SIGTERM.

That one server already gives you:

  • JSON success and error encoding for Handle
  • built-in GET /livez, GET /readyz, and GET /version
  • request IDs and correlation IDs
  • access logging and panic recovery
  • OpenTelemetry request tracing and request metrics
  • Run(...)-path connection metrics
  • readiness transitions and graceful shutdown on SIGINT and SIGTERM
  • conservative timeout and request body defaults
  • built-in use of global OpenTelemetry providers and propagators unless you override them

When the service needs application-specific policy on top of that baseline, add global middleware with WithMiddleware(...) or route-local behavior with WithEndpointMiddleware(...) rather than replacing the whole setup.

By default, panic recovery logs the panic and stack trace, returns a best-effort JSON 500 when the response is still uncommitted, and leaves committed responses alone.

In practice, you get a real HTTP baseline without hand-building the http.Server lifecycle, middleware stack, probes, IDs, telemetry, and default request/response behavior yourself.

The Core Model

Servekit is deliberately built around one normal path and one escape hatch.

Normal path

Use Handle for the endpoints that naturally want to:

  1. inspect the request
  2. do application work
  3. return one payload or one error
s.Handle(http.MethodGet, "/users/me", func(r *http.Request) (any, error) {
	return map[string]string{
		"id":   "123",
		"name": "jared",
	}, nil
})
Escape hatch

Use HandleHTTP when the endpoint needs direct net/http control, such as streaming, proxying, upgrades, or mounting an existing http.Handler:

s.HandleHTTP(http.MethodGet, "/events", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/event-stream")
	w.Header().Set("Cache-Control", "no-cache")
	w.WriteHeader(http.StatusOK)

	flusher, ok := w.(http.Flusher)
	if !ok {
		http.Error(w, "streaming unsupported", http.StatusInternalServerError)
		return
	}

	for i := 0; i < 3; i++ {
		_, _ = fmt.Fprintf(w, "data: tick %d\n\n", i)
		flusher.Flush()
		time.Sleep(500 * time.Millisecond)
	}
}))

Typical reasons are streaming, server-sent events, reverse proxying, protocol upgrades, or handlers that already exist as http.Handler. Servekit preserves runtime writer capabilities such as http.Flusher, http.Hijacker, and the io.ReaderFrom fast path when the underlying writer supports them, so the raw path stays credible.

Servekit also uses the underlying http.ServeMux routing model rather than inventing its own router DSL. That is intentional: the package is meant to standardize the service baseline around the standard library, not to replace the standard library routing story.

Why This Works

Servekit rests on three choices:

  1. It keeps the standard library visible.
  2. It ships a coherent operational baseline instead of scattered one-off setup.
  3. It lets the service become more specialized without forcing a rewrite onto a different abstraction model.

That is why the package can stay small without feeling toy-sized.

Advanced Capabilities

Servekit has a short normal path, but it is not boxed into only the defaults. Advanced hooks include:

  • global and route-level custom middleware
  • custom success and error encoders, globally or per endpoint
  • integration with an existing http.ServeMux
  • mounting Handler() into your own http.Server
  • explicit readiness control with SetReady(...)
  • custom slog and http.Server.ErrorLog wiring
  • CORS configuration
  • OpenTelemetry provider, propagator, and labeling customization
  • raw-response handling for streaming, proxying, and hijacking

The advanced path is documented in docs/advanced.md, including composition patterns for combining several hooks without losing the main Servekit model.

Documentation

Examples

Runnable programs live in examples/, which includes a guided tour of the example set.

Recommended reading order:

  1. examples/basic
  2. examples/telemetry
  3. examples/endpoint-controls
  4. examples/custom-encoding
  5. examples/readiness
  6. examples/logging
  7. examples/cors
  8. examples/external-server
  9. examples/advanced-composition
  10. examples/streaming
  11. examples/reverse-proxy
  12. examples/response-capture

API Reference

The canonical symbol-level API documentation should live in Go doc comments so it stays accurate in editors and Go tooling. The repository-level companion is docs/api.md, which groups the exported surface into a human-oriented map.

Maintenance

Servekit is a small open source library maintained on a best-effort basis.

The active development line lives on main, and that is the only line actively maintained unless explicitly noted otherwise. The minimum supported Go version is declared in go.mod, and the Go versions currently verified in CI are listed in .github/workflows/ci.yaml.

Compatibility-impacting changes should be called out explicitly in release notes or release descriptions. Long-lived maintenance branches and backports are not planned unless explicitly noted.

License

MIT

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

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

func CorrelationIDFromContext(ctx context.Context) string

CorrelationIDFromContext returns the correlation ID inserted by CorrelationID.

func Error

func Error(status int, message string, err error) error

Error constructs an HTTPError value.

func RequestIDFromContext

func RequestIDFromContext(ctx context.Context) string

RequestIDFromContext returns the request ID inserted by RequestID.

func SpanIDFromContext

func SpanIDFromContext(ctx context.Context) string

SpanIDFromContext returns the active span ID for the request context.

func TraceIDFromContext

func TraceIDFromContext(ctx context.Context) string

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

type ErrorEncoder func(http.ResponseWriter, *http.Request, error) error

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.

func (HTTPError) Error

func (e HTTPError) Error() string

Error implements error.

func (HTTPError) Unwrap

func (e HTTPError) Unwrap() error

Unwrap returns the wrapped cause for errors.Is/errors.As.

type HandlerFunc

type HandlerFunc func(r *http.Request) (any, error)

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

type Middleware func(http.Handler) http.Handler

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

func WithAccessLogEnabled(enabled bool) Option

WithAccessLogEnabled enables or disables request access logging middleware.

func WithAddr

func WithAddr(addr string) Option

WithAddr sets the TCP listen address (for example, ":8080").

func WithBuildInfo

func WithBuildInfo(version, commit, date string) Option

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

func WithCorrelationIDEnabled(enabled bool) Option

WithCorrelationIDEnabled enables or disables correlation ID middleware.

func WithDefaultEndpointsEnabled

func WithDefaultEndpointsEnabled(enabled bool) Option

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

func WithHTTPServerErrorLog(logger *log.Logger) Option

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

func WithHTTPServerErrorLogLevel(level slog.Level) Option

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

func WithHealthHandler(handler http.Handler) Option

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

func WithIdleTimeout(timeout time.Duration) Option

WithIdleTimeout sets http.Server.IdleTimeout.

func WithLogger

func WithLogger(logger *slog.Logger) Option

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

func WithMaxHeaderBytes(n int) Option

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

func WithMux(mux *http.ServeMux) Option

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

func WithOTelAttributes(fn func(*http.Request) []attribute.KeyValue) Option

WithOTelAttributes appends request attributes to spans and metrics.

func WithOTelPanicMetricEnabled

func WithOTelPanicMetricEnabled(enabled bool) Option

WithOTelPanicMetricEnabled enables or disables panic counter metrics.

func WithOpenTelemetryEnabled

func WithOpenTelemetryEnabled(enabled bool) Option

WithOpenTelemetryEnabled toggles Servekit's built-in OTel middleware.

func WithPanicPropagation

func WithPanicPropagation(enabled bool) Option

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

func WithReadHeaderTimeout(timeout time.Duration) Option

WithReadHeaderTimeout sets http.Server.ReadHeaderTimeout.

func WithReadTimeout

func WithReadTimeout(timeout time.Duration) Option

WithReadTimeout sets http.Server.ReadTimeout.

func WithReadinessChecks

func WithReadinessChecks(checks ...ReadinessCheck) Option

WithReadinessChecks appends checks evaluated by the built-in /readyz endpoint.

func WithRecoveryEnabled

func WithRecoveryEnabled(enabled bool) Option

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

func WithRequestBodyLimit(n int64) Option

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

func WithRequestIDEnabled(enabled bool) Option

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

func WithRouteLabeler(fn func(*http.Request) string) Option

WithRouteLabeler overrides the low-cardinality route label strategy.

func WithShutdownDrainDelay

func WithShutdownDrainDelay(delay time.Duration) Option

WithShutdownDrainDelay waits after becoming unready before shutdown begins.

func WithShutdownTimeout

func WithShutdownTimeout(timeout time.Duration) Option

WithShutdownTimeout sets the timeout used for graceful shutdown.

func WithSpanNameFormatter

func WithSpanNameFormatter(fn func(*http.Request, string) string) Option

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

func WithWriteTimeout(timeout time.Duration) Option

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

type ReadinessCheck func(context.Context) error

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

type ResponseEncoder func(http.ResponseWriter, *http.Request, any) error

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

func New(opts ...Option) *Server

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

func (s *Server) Handler() http.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) Ready

func (s *Server) Ready() bool

Ready reports the current readiness state exposed by /readyz.

func (*Server) Run

func (s *Server) Run(ctx context.Context) error

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.

func (*Server) SetReady

func (s *Server) SetReady(ready bool)

SetReady overrides the readiness state reported by the built-in /readyz route.

Calling SetReady opts the server into explicit readiness control. After SetReady has been called, Run will not force readiness true during startup.

Directories

Path Synopsis
examples
basic command
cors command
custom-encoding command
external-server command
logging command
readiness 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.

Jump to

Keyboard shortcuts

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