github.com/lastbackend/toolkit@v0.0.0-20241020043710-cafa37b95aad/pkg/server/http/errors/http.go (about)

     1  package errors
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"google.golang.org/grpc/codes"
     9  	"google.golang.org/grpc/status"
    10  )
    11  
    12  var GrpcErrorHandlerFunc = HTTP.ParseGrpcError
    13  var HTTP Http
    14  
    15  type Http struct {
    16  	Code    int    `json:"code"`
    17  	Status  string `json:"status"`
    18  	Message string `json:"message"`
    19  }
    20  
    21  func (Http) Unauthorized(w http.ResponseWriter, msg ...string) {
    22  	HTTP.getUnauthorized(msg...).send(w)
    23  }
    24  
    25  func (Http) Forbidden(w http.ResponseWriter, msg ...string) {
    26  	HTTP.getForbidden(msg...).send(w)
    27  }
    28  
    29  func (Http) NotAllowed(w http.ResponseWriter, msg ...string) {
    30  	HTTP.getNotAllowed(msg...).send(w)
    31  }
    32  
    33  func (Http) BadRequest(w http.ResponseWriter, msg ...string) {
    34  	HTTP.getBadRequest(msg...).send(w)
    35  }
    36  
    37  func (Http) NotFound(w http.ResponseWriter, args ...string) {
    38  	HTTP.getNotFound(args...).send(w)
    39  }
    40  
    41  func (Http) InternalServerError(w http.ResponseWriter, msg ...string) {
    42  	HTTP.getInternalServerError(msg...).send(w)
    43  }
    44  
    45  func (Http) BadGateway(w http.ResponseWriter) {
    46  	HTTP.getBadGateway().send(w)
    47  }
    48  
    49  func (Http) PaymentRequired(w http.ResponseWriter, msg ...string) {
    50  	HTTP.getPaymentRequired(msg...).send(w)
    51  }
    52  
    53  func (Http) NotImplemented(w http.ResponseWriter, msg ...string) {
    54  	HTTP.getPaymentRequired(msg...).send(w)
    55  }
    56  
    57  func (Http) BadParameter(w http.ResponseWriter, args ...string) {
    58  	HTTP.getBadParameter(args...).send(w)
    59  }
    60  
    61  func (Http) InvalidJSON(w http.ResponseWriter, msg ...string) {
    62  	HTTP.getIncorrectJSON(msg...).send(w)
    63  }
    64  
    65  func (Http) InvalidXML(w http.ResponseWriter, msg ...string) {
    66  	HTTP.getIncorrectXML(msg...).send(w)
    67  }
    68  
    69  func (h Http) send(w http.ResponseWriter) {
    70  	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    71  	w.WriteHeader(h.Code)
    72  	response, _ := json.Marshal(h)
    73  	w.Write(response)
    74  }
    75  
    76  // ===================================================================================================================
    77  // ============================================= INTERNAL HELPER METHODS =============================================
    78  // ===================================================================================================================
    79  
    80  func (Http) getUnauthorized(msg ...string) *Http {
    81  	return getHttpError(http.StatusUnauthorized, msg...)
    82  }
    83  
    84  func (Http) getForbidden(msg ...string) *Http {
    85  	return getHttpError(http.StatusForbidden, msg...)
    86  }
    87  
    88  func (Http) getNotAllowed(msg ...string) *Http {
    89  	return getHttpError(http.StatusMethodNotAllowed, msg...)
    90  }
    91  
    92  func (Http) getPaymentRequired(msg ...string) *Http {
    93  	return getHttpError(http.StatusPaymentRequired, msg...)
    94  }
    95  
    96  func (Http) getUnknown(msg ...string) *Http {
    97  	return getHttpError(http.StatusInternalServerError, msg...)
    98  }
    99  
   100  func (Http) getInternalServerError(msg ...string) *Http {
   101  	return getHttpError(http.StatusInternalServerError, msg...)
   102  }
   103  
   104  func (Http) getBadGateway() *Http {
   105  	return getHttpError(http.StatusBadGateway)
   106  }
   107  
   108  func (Http) getNotImplemented(msg ...string) *Http {
   109  	return getHttpError(http.StatusNotImplemented, msg...)
   110  }
   111  
   112  func (Http) getBadRequest(msg ...string) *Http {
   113  	return getHttpError(http.StatusBadRequest, msg...)
   114  }
   115  
   116  func (Http) getNotFound(args ...string) *Http {
   117  	message := "Not Found"
   118  	for i, a := range args {
   119  		switch i {
   120  		case 0:
   121  			message = fmt.Sprintf("%s not found", toUpperFirstChar(a))
   122  		default:
   123  			panic("Wrong parameter count: (is allowed from 0 to 1)")
   124  		}
   125  	}
   126  	return &Http{
   127  		Code:    http.StatusNotFound,
   128  		Status:  http.StatusText(http.StatusNotFound),
   129  		Message: message,
   130  	}
   131  }
   132  
   133  func (Http) getNotUnique(name string) *Http {
   134  	return &Http{
   135  		Code:    http.StatusBadRequest,
   136  		Status:  StatusNotUnique,
   137  		Message: fmt.Sprintf("%s is already in use", toUpperFirstChar(name)),
   138  	}
   139  }
   140  
   141  func (Http) getIncorrectJSON(msg ...string) *Http {
   142  	message := "Incorrect json"
   143  	for i, m := range msg {
   144  		switch i {
   145  		case 0:
   146  			message = m
   147  		default:
   148  			panic("Wrong parameter count: (is allowed from 0 to 1)")
   149  		}
   150  	}
   151  	return &Http{
   152  		Code:    http.StatusBadRequest,
   153  		Status:  StatusIncorrectJson,
   154  		Message: message,
   155  	}
   156  }
   157  
   158  func (Http) getIncorrectXML(msg ...string) *Http {
   159  	message := "Incorrect json"
   160  	for i, m := range msg {
   161  		switch i {
   162  		case 0:
   163  			message = m
   164  		default:
   165  			panic("Wrong parameter count: (is allowed from 0 to 1)")
   166  		}
   167  	}
   168  	return &Http{
   169  		Code:    http.StatusBadRequest,
   170  		Status:  StatusIncorrectXml,
   171  		Message: message,
   172  	}
   173  }
   174  
   175  func (Http) getAllocatedParameter(args ...string) *Http {
   176  	message := "Value is in use"
   177  	for i, a := range args {
   178  		switch i {
   179  		case 0:
   180  			message = fmt.Sprintf("%s is already in use", toUpperFirstChar(a))
   181  		default:
   182  			panic("Wrong parameter count: (is allowed from 0 to 1)")
   183  		}
   184  	}
   185  	return &Http{
   186  		Code:    http.StatusBadRequest,
   187  		Status:  StatusBadParameter,
   188  		Message: message,
   189  	}
   190  }
   191  
   192  func (Http) getBadParameter(args ...string) *Http {
   193  	message := "Bad parameter"
   194  	for i, a := range args {
   195  		switch i {
   196  		case 0:
   197  			message = fmt.Sprintf("Bad %s parameter", a)
   198  		default:
   199  			panic("Wrong parameter count: (is allowed from 0 to 1)")
   200  		}
   201  	}
   202  	return &Http{
   203  		Code:    http.StatusBadRequest,
   204  		Status:  StatusBadParameter,
   205  		Message: message,
   206  	}
   207  }
   208  
   209  func getHttpError(code int, msg ...string) *Http {
   210  	httpStatus := http.StatusText(code)
   211  	httpMessage := http.StatusText(code)
   212  
   213  	for i, m := range msg {
   214  		switch i {
   215  		case 0:
   216  			httpStatus = m
   217  		default:
   218  			panic("Wrong parameter count: (is allowed from 0 to 1)")
   219  		}
   220  	}
   221  	return &Http{
   222  		Code:    code,
   223  		Status:  httpMessage,
   224  		Message: httpStatus,
   225  	}
   226  }
   227  
   228  func (h Http) ParseGrpcError(w http.ResponseWriter, err error) {
   229  	st, ok := status.FromError(err)
   230  	if !ok {
   231  		h.InternalServerError(w, err.Error())
   232  		return
   233  	}
   234  	getHttpError(httpStatusFromCode(st.Code()), st.Message()).send(w)
   235  }
   236  
   237  func httpStatusFromCode(code codes.Code) int {
   238  	switch code {
   239  	case codes.OK:
   240  		return http.StatusOK
   241  	case codes.Canceled:
   242  		return http.StatusRequestTimeout
   243  	case codes.Unknown:
   244  		return http.StatusInternalServerError
   245  	case codes.InvalidArgument:
   246  		return http.StatusBadRequest
   247  	case codes.DeadlineExceeded:
   248  		return http.StatusGatewayTimeout
   249  	case codes.NotFound:
   250  		return http.StatusNotFound
   251  	case codes.AlreadyExists:
   252  		return http.StatusConflict
   253  	case codes.PermissionDenied:
   254  		return http.StatusForbidden
   255  	case codes.Unauthenticated:
   256  		return http.StatusUnauthorized
   257  	case codes.ResourceExhausted:
   258  		return http.StatusTooManyRequests
   259  	case codes.FailedPrecondition:
   260  		// Note, this deliberately
   261  		return http.StatusBadRequest
   262  	case codes.Aborted:
   263  		return http.StatusConflict
   264  	case codes.OutOfRange:
   265  		return http.StatusBadRequest
   266  	case codes.Unimplemented:
   267  		return http.StatusNotImplemented
   268  	case codes.Internal:
   269  		return http.StatusInternalServerError
   270  	case codes.Unavailable:
   271  		return http.StatusServiceUnavailable
   272  	case codes.DataLoss:
   273  		return http.StatusInternalServerError
   274  	}
   275  	return http.StatusInternalServerError
   276  }