Files
terminalShop/api/middleware/ratelimit.go
marcusDenslow 8ca209a4cc feat: add cart/auth/stripe metrics and slog-based log-level counter
Adds Prometheus instrumentation across the checkout funnel, auth flow,
Stripe calls, rate limiters, and HTTP middleware (inflight gauge, request
and response sizes). Introduces a slog handler that counts log lines by
level so the dashboard can show error/warn rates; existing log.Printf
calls are routed through slog and counted as info.

Backs the new "terminalshop — Service Overview" Grafana dashboard.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 13:38:24 +02:00

43 lines
1.3 KiB
Go

package middleware
import (
"net/http"
"time"
"strconv"
"github.com/go-chi/httprate"
"terminalShop/pkg/utils"
)
// RateLimitByIP returns a per-IP rate limiter for public endpoints.
func RateLimitByIP(limit int, window time.Duration) func(http.Handler) http.Handler {
return httprate.Limit(
limit, window,
httprate.WithKeyFuncs(httprate.KeyByIP),
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
RecordRateLimitRejection("ip")
utils.RespondError(w, http.StatusTooManyRequests, "RATE_LIMITED", "too many requests", nil)
}),
)
}
// RateLimitByUser returns a per-authenticated-user rate limiter for protected endpoints.
func RateLimitByUser(limit int, window time.Duration) func(http.Handler) http.Handler {
return httprate.Limit(
limit, window,
httprate.WithKeyFuncs(func(r *http.Request) (string, error) {
userID := UserIDFromContext(r.Context())
if userID == 0 {
// Fall back to IP if no user context (shouldn't happen on protected routes).
return httprate.KeyByIP(r)
}
return "user:" + strconv.FormatUint(uint64(userID), 10), nil
}),
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
RecordRateLimitRejection("user")
utils.RespondError(w, http.StatusTooManyRequests, "RATE_LIMITED", "too many requests", nil)
}),
)
}