API / internal /api /middleware /recovery.go
sshinmen's picture
Update HF Spaces deployment with latest changes
2e6b65c
Raw
History Blame Contribute Delete
2.22 kB
// Package middleware provides HTTP middleware components for the CLI Proxy API server.
// This file contains panic recovery middleware for graceful error handling.
package middleware
import (
"fmt"
"net/http"
"runtime/debug"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/router-for-me/CLIProxyAPI/v6/internal/application/dto"
)
// RecoveryMiddleware creates a Gin middleware that recovers from panics
// and returns a graceful error response instead of crashing the server.
// It logs the panic details including stack trace for debugging.
func RecoveryMiddleware(logger *logrus.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
requestID := c.GetString("request_id")
// Log the panic with stack trace if logger is available
if logger != nil {
logger.WithFields(logrus.Fields{
"panic": r,
"stacktrace": string(debug.Stack()),
"path": c.Request.URL.Path,
"method": c.Request.Method,
"client_ip": c.ClientIP(),
"request_id": requestID,
}).Error("Panic recovered in HTTP handler")
}
// Return graceful error response
c.AbortWithStatusJSON(http.StatusInternalServerError, dto.InternalErrorResponse{
Success: false,
RequestID: requestID,
Error: "An internal server error occurred",
})
}
}()
c.Next()
}
}
// SafeHandler wraps a handler function to catch panics at the handler level.
// This provides an additional layer of protection for critical endpoints.
func SafeHandler(handler gin.HandlerFunc) gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
requestID := c.GetString("request_id")
// Log the panic
logrus.WithFields(logrus.Fields{
"panic": fmt.Sprintf("%v", r),
"path": c.Request.URL.Path,
"method": c.Request.Method,
"request_id": requestID,
}).Error("Panic recovered in handler")
c.AbortWithStatusJSON(http.StatusInternalServerError, dto.InternalErrorResponse{
Success: false,
RequestID: requestID,
Error: "An internal server error occurred",
})
}
}()
handler(c)
}
}