feat(server): add /api/healthz endpoint with rich health info (#20)
Some checks failed
CI/CD Pipeline / Build Docker Cache (push) Successful in 17s
CI/CD Pipeline / CI Pipeline (push) Failing after 4m28s
CI/CD Pipeline / Trigger Docker Push (push) Has been skipped

Adds Kubernetes-style /api/healthz endpoint with status/version/uptime_seconds/timestamp.

Non-breaking — /api/health preserved. Includes unit test (passes locally) and BDD scenario (validated by CI).

Généré ~95% en autonomie par Mistral Vibe via workspace ICM ~/Work/Vibe/workspaces/healthz-feature/.

Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
This commit was merged in pull request #20.
This commit is contained in:
2026-05-03 12:25:54 +02:00
committed by arcodange
parent 8503d0824e
commit 045823ec8e
6 changed files with 128 additions and 1 deletions

View File

@@ -64,6 +64,7 @@ type Server struct {
validator *validation.Validator
userRepo user.UserRepository
userService user.UserService
startedAt time.Time
}
func NewServer(cfg *config.Config, readyCtx context.Context) *Server {
@@ -89,6 +90,7 @@ func NewServer(cfg *config.Config, readyCtx context.Context) *Server {
validator: validator,
userRepo: userRepo,
userService: userService,
startedAt: time.Now(),
}
s.setupRoutes()
return s
@@ -137,6 +139,9 @@ func (s *Server) setupRoutes() {
// Version endpoint at root level
s.router.Get("/api/version", s.handleVersion)
// Kubernetes-style health endpoint at root level
s.router.Get("/api/healthz", s.handleHealthz)
// API routes
s.router.Route("/api/v1", func(r chi.Router) {
r.Use(s.getAllMiddlewares()...)
@@ -358,6 +363,34 @@ func (s *Server) handleVersion(w http.ResponseWriter, r *http.Request) {
}
}
// HealthzResponse represents the Kubernetes-style health check response
type HealthzResponse struct {
Status string `json:"status"`
Version string `json:"version"`
UptimeSeconds int64 `json:"uptime_seconds"`
Timestamp time.Time `json:"timestamp"`
}
// handleHealthz godoc
//
// @Summary Kubernetes-style health check
// @Description Returns rich health info for liveness/readiness probes
// @Tags System/Health
// @Produce json
// @Success 200 {object} HealthzResponse
// @Router /healthz [get]
func (s *Server) handleHealthz(w http.ResponseWriter, r *http.Request) {
log.Trace().Msg("Healthz check requested")
resp := HealthzResponse{
Status: "healthy",
Version: version.Version,
UptimeSeconds: int64(time.Since(s.startedAt).Seconds()),
Timestamp: time.Now().UTC(),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
}
func (s *Server) Router() http.Handler {
return s.router
}