3.7 KiB
3.7 KiB
go-server
A minimal, production-ready, reusable HTTP server foundation for Go web services using Chi router and slog structured logging.
This package provides everything you need to spin up a secure, observable, and gracefully shutdown-capable web server with almost zero boilerplate.
Features
- Automatic TLS support (via env vars)
- Graceful shutdown on
SIGINTandSIGTERM - Structured JSON logging with
log/slog - Request ID generation and propagation
- Panic recovery with stack traces
- Structured access logging (method, path, duration, status, bytes, request_id)
- Built-in
/healthzand/readyzendpoints - Configurable timeouts (read, write, idle, shutdown)
- Functional options for clean configuration
- Full request-scoped contextual logging via
slog.Logger.With()
Installation
go get git.citc.tech/go/web/server
Quick Start
package main
import (
"os"
"github.com/go-chi/chi/v5"
"git.citc.tech/go/web/server"
)
func main() {
r := chi.NewRouter()
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello from your new service!"))
})
// Optional: custom logger, timeouts, etc.
srv := server.New(
server.WithRouter(r),
// server.WithLogger(customLogger),
// server.WithShutdownTimeout(20 * time.Second),
)
if err := srv.Start(); err != nil {
srv.Log.Error("server stopped with error", "error", err)
os.Exit(1)
}
}
That's it — your service is now running with full production features.
Configuration (Environment Variables)
| Variable | Description | Default |
|---|---|---|
APP_SERVER_ADDR |
Listen address (host:port) | :8080 |
APP_SERVER_TLS_KEY_FILE |
Path to TLS private key | (none) |
APP_SERVER_TLS_CERT_FILE |
Path to TLS certificate | (none) |
TLS is automatically enabled if both key and cert files exist and are readable.
Logging
- Uses
log/slogwith JSON output by default - All logs include timestamps and levels
- Access logs include duration, status, bytes, and request_id
- Panics are recovered and logged with full stack trace
- Request-scoped logging: use
server.LoggerFromContext(r.Context())in handlers for logs that automatically includerequest_id,method,path, etc.
Example Handler with Request-Scoped Logging
func protectedHandler(w http.ResponseWriter, r *http.Request) {
log := server.LoggerFromContext(r.Context())
log.Info("handling protected request", "action", "load_dashboard")
// All logs here automatically include request_id, method, path, etc.
log.Debug("fetching user data", "user_id", 123)
w.Write([]byte("Protected content"))
}
Middleware Stack (Applied by Default)
- Panic recovery (with structured error logging)
- Request ID generation (
X-Request-IDheader) - Structured request logging
You can override the router completely with WithRouter() — middleware will still apply unless you replace the router after New().
Options
server.WithLogger(logger *slog.Logger)
server.WithRouter(router chi.Router)
server.WithReadTimeout(duration time.Duration)
server.WithWriteTimeout(duration time.Duration)
server.WithIdleTimeout(duration time.Duration)
server.WithShutdownTimeout(duration time.Duration)
Health Endpoints
GET /healthz→ returns "ok" (200)GET /readyz→ returns "ready" (200)