Chi Server
A production-ready HTTP server package built on top of go-chi/chi with structured logging, request correlation, and graceful shutdown support.
Features
- π Simple Server Setup - Create production-ready HTTP servers with minimal boilerplate
- π Structured Logging - Built-in support for
log/slogwith JSON formatting - π Request Correlation - Automatic correlation ID generation and propagation
- π‘οΈ Graceful Shutdown - Context-based shutdown with configurable timeout
- π Request Logging - Automatic logging of all HTTP requests with duration, status, and correlation ID
- π― Middleware Ready - Pre-configured with essential middlewares (RequestID, RealIP, Recoverer)
Installation
go get your_module_path/chiserver
Quick Start
package main
import (
"log/slog"
"os"
"github.com/go-chi/chi/v5"
"your_module_path/chiserver"
)
func main() {
// Create logger
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
// Configure server
cfg := chiserver.Config{
Addr: ":8080",
Logger: logger,
}
// Create server with routes
server := chiserver.NewServer(cfg, func(r chi.Router) {
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("healthy"))
})
})
// Run with graceful shutdown
ctx := chiserver.WaitForSignal()
if err := server.Run(ctx); err != nil {
logger.Error("server failed", slog.String("error", err.Error()))
os.Exit(1)
}
}
Usage
Creating a Server
The NewServer function creates a new HTTP server with pre-configured middlewares:
cfg := chiserver.Config{
Addr: ":8080",
Logger: logger, // Optional: uses slog.Default() if nil
}
server := chiserver.NewServer(cfg, func(r chi.Router) {
// Define your routes here
r.Get("/api/users", getUsersHandler)
r.Post("/api/users", createUserHandler)
})
Middleware Stack
The server comes with the following middlewares pre-configured:
- RequestID - Generates a unique request ID
- CorrelationID - Propagates or generates correlation IDs via
X-Correlation-IDheader - RealIP - Extracts the real client IP from headers
- Recoverer - Recovers from panics and logs them
- RequestLogger - Logs all HTTP requests with structured logging
Correlation ID
Correlation IDs are automatically handled:
func handler(w http.ResponseWriter, r *http.Request) {
// Get correlation ID from context
corrID := chiserver.GetCorrID(r.Context())
// Use it in your logs
slog.Info("processing request", slog.String("correlation_id", corrID))
}
If a client sends an X-Correlation-ID header, it will be propagated. Otherwise, a new UUID is generated.
Custom Header Name
You can customize the correlation ID header name:
chiserver.CorrelationIDHeader = "X-Request-ID"
Graceful Shutdown
The server supports graceful shutdown with a 5-second timeout:
// Option 1: Use WaitForSignal for automatic signal handling
ctx := chiserver.WaitForSignal()
server.Run(ctx)
// Option 2: Use custom context
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
server.Run(ctx)
The WaitForSignal() function creates a context that cancels on SIGINT or SIGTERM.
Request Logging
All requests are automatically logged with the following fields:
method- HTTP method (GET, POST, etc.)path- Request pathstatus- Response status codebytes- Response size in bytesremote- Client IP addresscorrelation_id- Request correlation IDduration- Request processing duration
Example log output:
{
"time": "2025-10-28T10:30:45Z",
"level": "INFO",
"msg": "request",
"method": "GET",
"path": "/api/users",
"status": 200,
"bytes": 1234,
"remote": "192.168.1.1:12345",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000",
"duration": 15000000
}
Configuration
Config Options
type Config struct {
Addr string // Server address (e.g., ":8080")
Logger *slog.Logger // Optional: structured logger
}
Route Configurator
The RouteConfigurator function allows you to define your application routes:
type RouteConfigurator func(r chi.Router)
You can organize routes using chiβs routing features:
server := chiserver.NewServer(cfg, func(r chi.Router) {
// Group routes with common prefix
r.Route("/api/v1", func(r chi.Router) {
r.Get("/users", listUsers)
r.Post("/users", createUser)
r.Get("/users/{id}", getUser)
})
// Add middleware to specific routes
r.Group(func(r chi.Router) {
r.Use(authMiddleware)
r.Get("/admin", adminHandler)
})
})
Dependencies
- go-chi/chi - Lightweight HTTP router
- google/uuid - UUID generation
- Standard library
log/slog- Structured logging
License
MIT License - see LICENSE file for details