Recipe: Go net/http handler scaffold
A production-ready HTTP handler skeleton with structured logging, request ID propagation, timeout middleware, and graceful shutdown.
package main
import (
"context"
"log/slog"
"net/http"
"os"
"time"
)
func main() {
h := slog.NewJSONHandler(os.Stderr, nil)
l := slog.New(h)
mux := http.NewServeMux()
mux.HandleFunc("GET /health", health(l))
srv := &http.Server{
Addr: ":8080",
Handler: requestID(timeout(30*time.Second, mux)),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
go func() {
l.Info("listening", "addr", srv.Addr)
if err := srv.ListenAndServe(); err != nil {
l.Error("server error", "err", err)
}
}()
// graceful shutdown omitted for brevity
select {}
}Middleware chain
func requestID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := r.Header.Get("X-Request-ID")
if id == "" {
id = "gen-" + time.Now().Format("20060102150405")
}
w.Header().Set("X-Request-ID", id)
ctx := context.WithValue(r.Context(), "rid", id)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func timeout(d time.Duration, next http.Handler) http.Handler {
return http.TimeoutHandler(next, d, "request timed out")
}Handler pattern
func health(l *slog.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l.InfoContext(r.Context(), "health check")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ok"}`))
}
}This scaffold uses only the standard library. For production, pair with the Meridian loader to enforce license checks before the handler serves traffic.