Files
dev-service/pkg/api/middleware/validate.go
itzaname edab21990f
All checks were successful
continuous-integration/drone/push Build is passing
Add request logging
2025-06-27 22:21:49 -04:00

66 lines
1.8 KiB
Go

package middleware
import (
"git.itzana.me/strafesnet/go-grpc/dev"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"net/http"
"strconv"
)
const (
HeaderAPIKey = "X-API-Key"
HeaderRateLimitBurst = "X-Rate-Limit-Burst"
HeaderRateLimitDaily = "X-Rate-Limit-Daily"
HeaderRateLimitMonthly = "X-Rate-Limit-Monthly"
// Error messages
ErrMsgAPIKeyRequired = "API key is required"
ErrMsgInternalServer = "Internal server error"
)
// ValidateRequest returns a middleware that validates API requests against the dev service
func ValidateRequest(service, permission string, conn *grpc.ClientConn) gin.HandlerFunc {
return func(ctx *gin.Context) {
// Get API key from the request header
apiKey := ctx.GetHeader(HeaderAPIKey)
if apiKey == "" {
ctx.JSON(http.StatusUnauthorized, gin.H{"error": ErrMsgAPIKeyRequired})
ctx.Abort()
return
}
// Create client and validate the API key
resp, err := dev.NewDevServiceClient(conn).Validate(ctx, &dev.APIValidationRequest{
Service: service,
Permission: permission,
Key: apiKey,
IP: ctx.ClientIP(),
Resource: ctx.Request.URL.String(),
})
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": ErrMsgInternalServer})
ctx.Abort()
log.WithError(err).Error(
"failed to validate API key",
)
return
}
// Set the remaining rate limits in the response headers
ctx.Header(HeaderRateLimitBurst, strconv.FormatUint(resp.RemainingBurst, 10))
ctx.Header(HeaderRateLimitDaily, strconv.FormatUint(resp.RemainingDaily, 10))
ctx.Header(HeaderRateLimitMonthly, strconv.FormatUint(resp.RemainingMonthly, 10))
if !resp.Valid {
ctx.JSON(int(resp.StatusCode), gin.H{"error": resp.ErrorMessage})
ctx.Abort()
return
}
ctx.Next()
}
}