// Package api wires pansy's HTTP surface: a gin engine with structured logging // and panic recovery, the versioned JSON API under /api/v1, and (via spa.go) the // embedded single-page-app fallback. Handlers stay thin — decode, call the // service layer, encode — so all business logic and permission checks live in // internal/service (added by later issues). package api import ( "log/slog" "net/http" "github.com/gin-gonic/gin" sloggin "github.com/samber/slog-gin" "gitea.stevedudenhoeffer.com/steve/pansy/internal/config" ) func init() { // Quiet gin's default debug output; we log via slog-gin instead. gin.SetMode(gin.ReleaseMode) } // New builds the gin engine with the standard middleware stack and registers the // API routes. The embedded SPA fallback is registered separately by the caller // via RegisterSPA (see spa.go) so the API can be built and tested without a web // build present. func New(cfg *config.Config) *gin.Engine { r := gin.New() r.Use(sloggin.New(slog.Default()), gin.Recovery()) if err := r.SetTrustedProxies(cfg.TrustedProxies); err != nil { slog.Warn("api: failed to set trusted proxies", "error", err) } v1 := r.Group("/api/v1") v1.GET("/healthz", healthz) return r } // healthz is a liveness probe: always returns {"ok": true} when the server is up. func healthz(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true}) }