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:
2026-03-21 13:41:54 +03:00
parent 6b901c931e
commit cea75d198b
12 changed files with 1215 additions and 0 deletions

56
server/middleware.go Normal file
View File

@@ -0,0 +1,56 @@
package server
import "net/http"
// Middleware wraps an http.Handler to add behavior.
// This is the server-side counterpart of the client middleware type
// func(http.RoundTripper) http.RoundTripper.
type Middleware func(http.Handler) http.Handler
// Chain composes middlewares so that Chain(A, B, C)(handler) == A(B(C(handler))).
// Middlewares are applied from right to left: C wraps handler first, then B wraps
// the result, then A wraps last. This means A is the outermost layer and sees
// every request first.
func Chain(mws ...Middleware) Middleware {
return func(h http.Handler) http.Handler {
for i := len(mws) - 1; i >= 0; i-- {
h = mws[i](h)
}
return h
}
}
// statusWriter wraps http.ResponseWriter to capture the response status code.
// It implements Unwrap() so that http.ResponseController can access the
// underlying ResponseWriter's optional interfaces (Flusher, Hijacker, etc.).
type statusWriter struct {
http.ResponseWriter
status int
written bool
}
// WriteHeader captures the status code and delegates to the underlying writer.
func (w *statusWriter) WriteHeader(code int) {
if !w.written {
w.status = code
w.written = true
}
w.ResponseWriter.WriteHeader(code)
}
// Write delegates to the underlying writer, defaulting status to 200 if
// WriteHeader was not called explicitly.
func (w *statusWriter) Write(b []byte) (int, error) {
if !w.written {
w.status = http.StatusOK
w.written = true
}
return w.ResponseWriter.Write(b)
}
// Unwrap returns the underlying ResponseWriter. This is required for
// http.ResponseController to detect optional interfaces like http.Flusher
// and http.Hijacker on the original writer.
func (w *statusWriter) Unwrap() http.ResponseWriter {
return w.ResponseWriter
}