60 lines
1.8 KiB
Go
60 lines
1.8 KiB
Go
package httpapp
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
|
|
"gitea.avt.data-center.id/othman.suseno/atlas/internal/errors"
|
|
)
|
|
|
|
// writeError writes a structured error response
|
|
func writeError(w http.ResponseWriter, err error) {
|
|
// Check if it's an APIError
|
|
if apiErr, ok := err.(*errors.APIError); ok {
|
|
writeJSON(w, apiErr.HTTPStatus, apiErr)
|
|
return
|
|
}
|
|
|
|
// Default to internal server error
|
|
log.Printf("unhandled error: %v", err)
|
|
apiErr := errors.ErrInternal("an unexpected error occurred")
|
|
writeJSON(w, apiErr.HTTPStatus, apiErr)
|
|
}
|
|
|
|
// handleServiceError handles errors from service operations with graceful degradation
|
|
func (a *App) handleServiceError(serviceName string, err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
// Log the error for debugging
|
|
log.Printf("%s service error: %v", serviceName, err)
|
|
|
|
// For service errors, we might want to continue operation
|
|
// but log the issue. The API request can still succeed
|
|
// even if service configuration fails (desired state is stored)
|
|
return errors.ErrServiceUnavailable(serviceName).WithDetails(err.Error())
|
|
}
|
|
|
|
// recoverPanic recovers from panics and returns a proper error response
|
|
func recoverPanic(w http.ResponseWriter, r *http.Request) {
|
|
if rec := recover(); rec != nil {
|
|
log.Printf("panic recovered: %v", rec)
|
|
err := errors.ErrInternal("an unexpected error occurred")
|
|
writeError(w, err)
|
|
}
|
|
}
|
|
|
|
// errorMiddleware wraps handlers with panic recovery
|
|
func (a *App) errorMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
defer recoverPanic(w, r)
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// writeJSONError is a convenience function for JSON error responses
|
|
func writeJSONError(w http.ResponseWriter, code int, message string) {
|
|
writeJSON(w, code, map[string]string{"error": message})
|
|
}
|