Files
old-svijetlastrana/server/router/routeutils/response.go
2018-06-01 16:14:56 +02:00

242 lines
7.6 KiB
Go

package routeutils
import (
"database/sql"
"fmt"
"net"
"net/http"
"os/exec"
"reflect"
"strings"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/go-sql-driver/mysql"
"github.com/labstack/echo"
)
// resultWrapper has fields for standard message responses
type resultWrapper struct {
Error bool `json:"error,omitempty"`
Message string `json:"message,omitempty"`
Redirect bool `json:"redirect,omitempty"`
Data interface{} `json:"data,omitempty"`
}
// ResponseNoContent returns a standard API success with no content response
func ResponseNoContent(c echo.Context, data interface{}) error {
return c.NoContent(http.StatusNoContent)
}
// ResponseAPIOK returns a standard API success response
func ResponseAPIOK(c echo.Context, data interface{}) error {
return c.JSON(http.StatusOK, data)
}
// ResponseAPIErrorWithData returns a standard API error with additional data to the response
func ResponseAPIErrorWithData(c echo.Context, status int, message string, redirect bool, data interface{}) error {
returnValue := resultWrapper{
Error: true,
Message: message,
Redirect: redirect,
Data: data,
}
return c.JSON(status, returnValue)
}
// ResponseAPIError returns a standard API error to the response
func ResponseAPIError(c echo.Context, status int, message string, redirect bool) error {
returnValue := resultWrapper{
Error: true,
Message: message,
Redirect: redirect,
}
return c.JSON(status, returnValue)
}
// ResponseAPIAuthError returns a standard API auth error to the response
func ResponseAPIAuthError(c echo.Context, message string, redirect bool) error {
return ResponseAPIError(c, http.StatusUnauthorized, message, redirect)
}
// ResponseAPIAuthorizationError returns a standard API auth error to the response
func ResponseAPIAuthorizationError(c echo.Context) error {
return ResponseAPIError(c, http.StatusForbidden, "Forbidden by controller", false)
}
// ResponseAPIServiceError returns a standard API service unavailable error to the response
func ResponseAPIServiceError(c echo.Context, message string) error {
return ResponseAPIError(c, http.StatusServiceUnavailable, message, false)
}
// ResponseAPIValidationError returns a standard API validation error to the response
func ResponseAPIValidationError(c echo.Context, message string) error {
return ResponseAPIError(c, http.StatusUnprocessableEntity, message, false)
}
// ResponseAPICustomValidationError returns a standard API validation error with custom data to the response
func ResponseAPICustomValidationError(c echo.Context, message string, data interface{}) error {
return ResponseAPIErrorWithData(c, http.StatusUnprocessableEntity, message, false, data)
}
// ResponseAPIFieldValidationError returns a standard API field validation error to the response
func ResponseAPIFieldValidationError(c echo.Context, field string, message string) error {
err := errors.NewValidationError(field, message)
return HandleAPIError(c, err)
}
// ResponseAPINotFoundError returns a standard API not found error to the response
func ResponseAPINotFoundError(c echo.Context) error {
return ResponseAPIError(c, http.StatusNotFound, "Not Found", false)
}
//ResponseAPINotEligibleError returns a standard API not eligible to the response
func ResponseAPINotEligibleError(c echo.Context) error {
return ResponseAPIError(c, http.StatusForbidden, "Member does not have active insurance coverage", false)
}
//ResponseAPINotEligibleWithMessageError returns a standard API not eligible to the response with custom message
func ResponseAPINotEligibleWithMessageError(c echo.Context, message string) error {
return ResponseAPIError(c, http.StatusForbidden, message, false)
}
//ResponseAPIPasswordResetFailed returns a standard API error when password reset fails
func ResponseAPIPasswordResetFailed(c echo.Context, message string) error {
return ResponseAPIError(c, http.StatusForbidden, message, false)
}
func ignoreDefaultWrappedErrors(c echo.Context, errorToHandle *errors.WrappedError, handler func(echo.Context, error) error) error {
err := errorToHandle.GetOriginalError()
if err != nil {
switch e := (*err).(type) {
case *errors.ValidationError:
case *errors.NotAuthorizedError:
case *errors.HTTPError:
case awserr.Error:
default:
if e != sql.ErrNoRows {
c.Logger().Errorf("%s", e.Error())
}
}
return handler(c, *err)
}
return nil
}
// HandleAPIError applies the default error handling to the response
func HandleAPIError(c echo.Context, errorToHandle error) (err error) {
statusCode := http.StatusServiceUnavailable
errorMessage := "Service Unavailable"
if errorToHandle != nil {
logger := c.Logger()
errorString := errorToHandle.Error()
switch e := errorToHandle.(type) {
case *errors.WrappedError:
return ignoreDefaultWrappedErrors(c, e, HandleAPIError)
case *errors.ApplicationError:
logger.Errorf("Application Error: %s - %v", e.Path, e.Message)
case *errors.ValidationError:
return ResponseAPIValidationError(c, errorString)
case *errors.NotAuthorizedError:
statusCode = http.StatusUnauthorized
errorMessage = errorString
case *errors.HTTPError:
statusCode = e.Status
errorMessage = e.Message
case *mysql.MySQLError:
logger.Errorf("MySQL Error: %v - %v", e.Number, e.Message)
errorMessage = "Service temporarily unavailable"
case net.Error:
logger.Errorf("Network/Connection error: %v", e.Error())
errorMessage = "Service temporarily unavailable"
case *echo.HTTPError:
statusCode = e.Code
errorMessage = fmt.Sprint(e.Message)
case *exec.ExitError:
logger.Errorf("Exec Error: %s - %v", e.ProcessState, e.Error())
default:
if e == sql.ErrNoRows {
logger.Debugf("SQL Error: %v", e.Error())
return ResponseAPINotFoundError(c)
} else if e == sql.ErrTxDone || strings.HasPrefix(errorString, "sql: ") {
logger.Errorf("SQL Error: %v", e.Error())
return ResponseAPIServiceError(c, "Service temporarily unavailable")
}
logger.Errorf("%v: %v", reflect.TypeOf(e), e.Error())
}
}
return ResponseAPIError(c, statusCode, errorMessage, false)
}
// HandleHTMLError applies the default error handling to the response
func HandleHTMLError(c echo.Context, errorToHandle error) error {
statusCode := http.StatusServiceUnavailable
errorMessage := "Service Unavailable"
if errorToHandle != nil {
logger := c.Logger()
errorString := errorToHandle.Error()
switch e := errorToHandle.(type) {
case *errors.WrappedError:
return ignoreDefaultWrappedErrors(c, e, HandleHTMLError)
case *errors.ApplicationError:
logger.Errorf("Application Error: %s - %v", e.Path, e.Message)
case *errors.ValidationError:
return ResponseAPIValidationError(c, errorString)
case *errors.NotAuthorizedError:
return ResponseAPIError(c, http.StatusUnauthorized, errorString, false)
case *errors.HTTPError:
errorMessage = e.Message
case *mysql.MySQLError:
logger.Errorf("MySQL Error: %v - %v", e.Number, e.Message)
errorMessage = "Service temporarily unavailable"
case net.Error:
logger.Errorf("Network/Connection error: %v", e.Error())
errorMessage = "Service temporarily unavailable"
case *echo.HTTPError:
logger.Errorf("%v: %v - %v", reflect.TypeOf(e), e.Code, e.Message)
statusCode = e.Code
default:
if e == sql.ErrNoRows {
logger.Debugf("SQL Error: %v", e.Error())
statusCode = http.StatusNotFound
errorMessage = "Not Found"
} else if e == sql.ErrTxDone || strings.HasPrefix(errorString, "sql: ") {
logger.Errorf("SQL Error: %v", e.Error())
errorMessage = "Service temporarily unavailable"
} else {
logger.Errorf("%v: %v", reflect.TypeOf(e), e.Error())
}
}
}
return c.HTML(statusCode, errorMessage)
}