From 880c9245ac1df17f8e6aed2b67919b85c92424ee Mon Sep 17 00:00:00 2001 From: NeelMalwatkar Date: Thu, 19 Feb 2026 00:37:39 -0500 Subject: [PATCH 1/3] fix: added http error codes --- errors/errors.go | 88 +++++++++++++++++++++++++ middlewares/error_handler.go | 121 +++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) diff --git a/errors/errors.go b/errors/errors.go index 984bc18..92b51dc 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -39,3 +39,91 @@ type Unauthorized struct { func (e *Unauthorized) Error() string { return e.Message } + +type MethodNotAllowed struct { + Message string +} + +func (e *MethodNotAllowed) Error() string { + return e.Message +} + +type Conflict struct { + Message string +} + +func (e *Conflict) Error() string { + return e.Message +} + +type Gone struct { + Message string +} + +func (e *Gone) Error() string { + return e.Message +} + +type UnsupportedMediaType struct { + Message string +} + +func (e *UnsupportedMediaType) Error() string { + return e.Message +} + +type UnprocessableEntity struct { + Message string +} + +func (e *UnprocessableEntity) Error() string { + return e.Message +} + +type TooManyRequests struct { + Message string +} + +func (e *TooManyRequests) Error() string { + return e.Message +} + +type InternalServerError struct { + Message string +} + +func (e *InternalServerError) Error() string { + return e.Message +} + +type BadGateway struct { + Message string +} + +func (e *BadGateway) Error() string { + return e.Message +} + +type GatewayTimeout struct { + Message string +} + +func (e *GatewayTimeout) Error() string { + return e.Message +} + +type RequestTimeout struct { + Message string +} + +func (e *RequestTimeout) Error() string { + return e.Message +} + +type NotImplemented struct { + Message string +} + +func (e *NotImplemented) Error() string { + return e.Message +} diff --git a/middlewares/error_handler.go b/middlewares/error_handler.go index 71b7735..7758174 100644 --- a/middlewares/error_handler.go +++ b/middlewares/error_handler.go @@ -20,6 +20,17 @@ func (e *ErrorHandler) Wrap(handler func(w http.ResponseWriter, r *http.Request) var serviceUnavailable *serviceErrors.ServiceUnavailable var forbiddenError *serviceErrors.Forbidden var unauthorizedError *serviceErrors.Unauthorized + var methodNotAllowedError *serviceErrors.MethodNotAllowed + var conflictError *serviceErrors.Conflict + var goneError *serviceErrors.Gone + var unsupportedMediaTypeError *serviceErrors.UnsupportedMediaType + var unprocessableEntityError *serviceErrors.UnprocessableEntity + var tooManyRequestsError *serviceErrors.TooManyRequests + var internalServerError *serviceErrors.InternalServerError + var badGatewayError *serviceErrors.BadGateway + var gatewayTimeoutError *serviceErrors.GatewayTimeout + var requestTimeoutError *serviceErrors.RequestTimeout + var notImplementedError *serviceErrors.NotImplemented err := handler(w, r) @@ -73,6 +84,116 @@ func (e *ErrorHandler) Wrap(handler func(w http.ResponseWriter, r *http.Request) return } + if errors.As(err, &methodNotAllowedError) { + render.Status(r, http.StatusMethodNotAllowed) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusMethodNotAllowed), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &conflictError) { + render.Status(r, http.StatusConflict) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusConflict), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &goneError) { + render.Status(r, http.StatusGone) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusGone), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &unsupportedMediaTypeError) { + render.Status(r, http.StatusUnsupportedMediaType) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusUnsupportedMediaType), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &unprocessableEntityError) { + render.Status(r, http.StatusUnprocessableEntity) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusUnprocessableEntity), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &tooManyRequestsError) { + render.Status(r, http.StatusTooManyRequests) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusTooManyRequests), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &internalServerError) { + render.Status(r, http.StatusInternalServerError) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusInternalServerError), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &badGatewayError) { + render.Status(r, http.StatusBadGateway) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusBadGateway), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &gatewayTimeoutError) { + render.Status(r, http.StatusGatewayTimeout) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusGatewayTimeout), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, &requestTimeoutError) { + render.Status(r, http.StatusRequestTimeout) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusRequestTimeout), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + + if errors.As(err, ¬ImplementedError) { + render.Status(r, http.StatusNotImplemented) + response := types.ErrorResponse{ + Status: http.StatusText(http.StatusNotImplemented), + Error: err.Error(), + } + render.JSON(w, r, response) + return + } + if err != nil { render.Status(r, http.StatusInternalServerError) response := types.ErrorResponse{ From d2d14bfbc263dfb1afc6d3d00ded1ca1136b3fe5 Mon Sep 17 00:00:00 2001 From: NeelMalwatkar Date: Mon, 23 Feb 2026 13:11:36 -0500 Subject: [PATCH 2/3] fix: refactored to use composition --- errors/errors.go | 139 ++++++----------------------------------------- 1 file changed, 18 insertions(+), 121 deletions(-) diff --git a/errors/errors.go b/errors/errors.go index 92b51dc..a8a6c91 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -1,129 +1,26 @@ package errors -type BadRequest struct { +type BaseError struct { Message string } -func (e *BadRequest) Error() string { +func (e *BaseError) Error() string { return e.Message } -type NotFound struct { - Message string -} - -func (e *NotFound) Error() string { - return e.Message -} - -type ServiceUnavailable struct { - Message string -} - -func (e *ServiceUnavailable) Error() string { - return e.Message -} - -type Forbidden struct { - Message string -} - -func (e *Forbidden) Error() string { - return e.Message -} - -type Unauthorized struct { - Message string -} - -func (e *Unauthorized) Error() string { - return e.Message -} - -type MethodNotAllowed struct { - Message string -} - -func (e *MethodNotAllowed) Error() string { - return e.Message -} - -type Conflict struct { - Message string -} - -func (e *Conflict) Error() string { - return e.Message -} - -type Gone struct { - Message string -} - -func (e *Gone) Error() string { - return e.Message -} - -type UnsupportedMediaType struct { - Message string -} - -func (e *UnsupportedMediaType) Error() string { - return e.Message -} - -type UnprocessableEntity struct { - Message string -} - -func (e *UnprocessableEntity) Error() string { - return e.Message -} - -type TooManyRequests struct { - Message string -} - -func (e *TooManyRequests) Error() string { - return e.Message -} - -type InternalServerError struct { - Message string -} - -func (e *InternalServerError) Error() string { - return e.Message -} - -type BadGateway struct { - Message string -} - -func (e *BadGateway) Error() string { - return e.Message -} - -type GatewayTimeout struct { - Message string -} - -func (e *GatewayTimeout) Error() string { - return e.Message -} - -type RequestTimeout struct { - Message string -} - -func (e *RequestTimeout) Error() string { - return e.Message -} - -type NotImplemented struct { - Message string -} - -func (e *NotImplemented) Error() string { - return e.Message -} +type BadRequest struct{ BaseError } +type NotFound struct{ BaseError } +type ServiceUnavailable struct{ BaseError } +type Forbidden struct{ BaseError } +type Unauthorized struct{ BaseError } +type MethodNotAllowed struct{ BaseError } +type Conflict struct{ BaseError } +type Gone struct{ BaseError } +type UnsupportedMediaType struct{ BaseError } +type UnprocessableEntity struct{ BaseError } +type TooManyRequests struct{ BaseError } +type InternalServerError struct{ BaseError } +type BadGateway struct{ BaseError } +type GatewayTimeout struct{ BaseError } +type RequestTimeout struct{ BaseError } +type NotImplemented struct{ BaseError } From 95b2d5733bb3132b260e202616846a3247a59826 Mon Sep 17 00:00:00 2001 From: NeelMalwatkar Date: Sat, 28 Mar 2026 20:44:37 -0400 Subject: [PATCH 3/3] fix: replace if with switch statement --- middlewares/error_handler.go | 219 ++++++++--------------------------- 1 file changed, 49 insertions(+), 170 deletions(-) diff --git a/middlewares/error_handler.go b/middlewares/error_handler.go index 7758174..a97d1b2 100644 --- a/middlewares/error_handler.go +++ b/middlewares/error_handler.go @@ -33,175 +33,54 @@ func (e *ErrorHandler) Wrap(handler func(w http.ResponseWriter, r *http.Request) var notImplementedError *serviceErrors.NotImplemented err := handler(w, r) - - if (errors.As(err, ¬FoundError)) || (errors.Is(err, storage.ErrNotFound)) { - render.Status(r, http.StatusNotFound) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusNotFound), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &badRequestError) { - render.Status(r, http.StatusBadRequest) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusBadRequest), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &serviceUnavailable) { - render.Status(r, http.StatusServiceUnavailable) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusServiceUnavailable), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &forbiddenError) { - render.Status(r, http.StatusForbidden) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusForbidden), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &unauthorizedError) { - render.Status(r, http.StatusUnauthorized) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusUnauthorized), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &methodNotAllowedError) { - render.Status(r, http.StatusMethodNotAllowed) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusMethodNotAllowed), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &conflictError) { - render.Status(r, http.StatusConflict) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusConflict), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &goneError) { - render.Status(r, http.StatusGone) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusGone), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &unsupportedMediaTypeError) { - render.Status(r, http.StatusUnsupportedMediaType) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusUnsupportedMediaType), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &unprocessableEntityError) { - render.Status(r, http.StatusUnprocessableEntity) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusUnprocessableEntity), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &tooManyRequestsError) { - render.Status(r, http.StatusTooManyRequests) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusTooManyRequests), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &internalServerError) { - render.Status(r, http.StatusInternalServerError) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusInternalServerError), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &badGatewayError) { - render.Status(r, http.StatusBadGateway) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusBadGateway), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &gatewayTimeoutError) { - render.Status(r, http.StatusGatewayTimeout) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusGatewayTimeout), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, &requestTimeoutError) { - render.Status(r, http.StatusRequestTimeout) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusRequestTimeout), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if errors.As(err, ¬ImplementedError) { - render.Status(r, http.StatusNotImplemented) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusNotImplemented), - Error: err.Error(), - } - render.JSON(w, r, response) - return - } - - if err != nil { - render.Status(r, http.StatusInternalServerError) - response := types.ErrorResponse{ - Status: http.StatusText(http.StatusInternalServerError), - Error: "encountered an unexpected server error: " + err.Error(), - } - render.JSON(w, r, response) - return - } + if err == nil { + return + } + + status := http.StatusInternalServerError + message := err.Error() + + switch { + case errors.As(err, ¬FoundError) || errors.Is(err, storage.ErrNotFound): + status = http.StatusNotFound + case errors.As(err, &badRequestError): + status = http.StatusBadRequest + case errors.As(err, &serviceUnavailable): + status = http.StatusServiceUnavailable + case errors.As(err, &forbiddenError): + status = http.StatusForbidden + case errors.As(err, &unauthorizedError): + status = http.StatusUnauthorized + case errors.As(err, &methodNotAllowedError): + status = http.StatusMethodNotAllowed + case errors.As(err, &conflictError): + status = http.StatusConflict + case errors.As(err, &goneError): + status = http.StatusGone + case errors.As(err, &unsupportedMediaTypeError): + status = http.StatusUnsupportedMediaType + case errors.As(err, &unprocessableEntityError): + status = http.StatusUnprocessableEntity + case errors.As(err, &tooManyRequestsError): + status = http.StatusTooManyRequests + case errors.As(err, &internalServerError): + status = http.StatusInternalServerError + case errors.As(err, &badGatewayError): + status = http.StatusBadGateway + case errors.As(err, &gatewayTimeoutError): + status = http.StatusGatewayTimeout + case errors.As(err, &requestTimeoutError): + status = http.StatusRequestTimeout + case errors.As(err, ¬ImplementedError): + status = http.StatusNotImplemented + default: + message = "encountered an unexpected server error: " + err.Error() + } + + render.Status(r, status) + render.JSON(w, r, types.ErrorResponse{ + Status: http.StatusText(status), + Error: message, + }) } }