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:
56
server/middleware.go
Normal file
56
server/middleware.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user