szabadpalya/api/internal/httpapi/public.go

71 lines
1.8 KiB
Go

package httpapi
import (
"errors"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/szabadpalya/api/internal/store"
)
// health is the readiness probe. It deliberately fails when Postgres is
// unreachable: an app that is running but cannot reach its database is not
// serving anything useful, and that is exactly the state a plain process check
// would miss.
//
// The body carries no error detail on purpose — this endpoint is
// unauthenticated and must not leak connection strings or stack traces.
func (s *Server) health(c *gin.Context) {
started := time.Now()
c.Header("Cache-Control", "no-store")
if err := s.store.Ping(c.Request.Context()); err != nil {
c.JSON(http.StatusServiceUnavailable, gin.H{
"status": "degraded", "database": "unreachable",
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "ok", "database": "ok",
"latencyMs": time.Since(started).Milliseconds(),
})
}
func (s *Server) listCampaigns(c *gin.Context) {
campaigns, err := s.store.ListCampaigns(c.Request.Context())
if err != nil {
s.fail(c, err)
return
}
c.JSON(http.StatusOK, campaigns)
}
func (s *Server) getCampaign(c *gin.Context) {
campaign, err := s.store.GetCampaignBySlug(c.Request.Context(), c.Param("slug"))
if errors.Is(err, store.ErrNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
if err != nil {
s.fail(c, err)
return
}
c.JSON(http.StatusOK, campaign)
}
func (s *Server) stats(c *gin.Context) {
st, err := s.store.PlatformStats(c.Request.Context())
if err != nil {
s.fail(c, err)
return
}
c.JSON(http.StatusOK, st)
}
// fail logs the real error and tells the client nothing about it.
func (s *Server) fail(c *gin.Context, err error) {
c.Error(err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"})
}