2022-11-23 04:06:29 -08:00
|
|
|
// The response package defines the success and error response type.
|
|
|
|
// It define a type [AppError] that represent the api error response.
|
|
|
|
// Its define a custom error handling for the api.
|
|
|
|
package response
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/api/internal/config"
|
|
|
|
)
|
|
|
|
|
|
|
|
// API error codes. These error code are the same used in guardian API.
|
2023-01-03 09:42:29 -08:00
|
|
|
// https://github.com/grpc/grpc-go/blob/master/codes/codes.go
|
2022-11-23 04:06:29 -08:00
|
|
|
const (
|
2023-01-03 09:42:29 -08:00
|
|
|
OK = iota
|
|
|
|
Canceled
|
|
|
|
Unknown
|
|
|
|
InvalidParam
|
|
|
|
DeadlineExceeded
|
|
|
|
NotFound
|
|
|
|
AlreadyExists
|
|
|
|
PermissionDenied
|
|
|
|
ResourceExhausted
|
|
|
|
FailedPrecondition
|
|
|
|
Aborted
|
|
|
|
OutOfRange
|
|
|
|
Unimplemented
|
|
|
|
Internal
|
|
|
|
Unavailable
|
|
|
|
DataLoss
|
|
|
|
Unauthenticated
|
2022-11-23 04:06:29 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
var enableStackTrace bool
|
|
|
|
|
|
|
|
// SetEnableStackTrace enable/disable send the stacktrace field in the response.
|
|
|
|
func SetEnableStackTrace(cfg config.AppConfig) {
|
|
|
|
if cfg.RunMode == config.RunModeDevelopmernt {
|
|
|
|
enableStackTrace = true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
enableStackTrace = false
|
|
|
|
}
|
|
|
|
|
|
|
|
// APIError api error response.
|
|
|
|
// This structure is defined to be aligned with the way the guardian API handles the error response.
|
|
|
|
type APIError struct {
|
|
|
|
StatusCode int `json:"-"`
|
|
|
|
Code int `json:"code"` // support to guardian-api code.
|
|
|
|
Message string `json:"message"`
|
|
|
|
Details []ErrorDetail `json:"details"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// ErrorDetail definition.
|
|
|
|
// This structure contains the requestID and the stacktrace of the error.
|
|
|
|
type ErrorDetail struct {
|
|
|
|
RequestID string `json:"request_id"`
|
|
|
|
StackTrace string `json:"stack_trace,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error interface implementation.
|
|
|
|
func (a APIError) Error() string {
|
|
|
|
return fmt.Sprintf("code: %d, message: %s, details: %v", a.Code, a.Message, a.Details)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewApiError create a new api response.
|
|
|
|
func NewApiError(ctx *fiber.Ctx, statusCode, code int, message string, err error) APIError {
|
|
|
|
detail := ErrorDetail{
|
|
|
|
RequestID: fmt.Sprintf("%v", ctx.Locals("requestid")),
|
|
|
|
}
|
|
|
|
if enableStackTrace && err != nil {
|
|
|
|
detail.StackTrace = fmt.Sprintf("%+v\n", err)
|
|
|
|
}
|
|
|
|
return APIError{
|
2023-01-03 09:42:29 -08:00
|
|
|
StatusCode: statusCode,
|
|
|
|
Code: code,
|
2022-11-23 04:06:29 -08:00
|
|
|
Message: message,
|
|
|
|
Details: []ErrorDetail{detail},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewInvalidParamError create a invalid param Error.
|
|
|
|
func NewInvalidParamError(ctx *fiber.Ctx, message string, err error) APIError {
|
|
|
|
if message == "" {
|
|
|
|
message = "INVALID PARAM"
|
|
|
|
}
|
|
|
|
detail := ErrorDetail{
|
|
|
|
RequestID: fmt.Sprintf("%v", ctx.Locals("requestid")),
|
|
|
|
}
|
|
|
|
if enableStackTrace && err != nil {
|
|
|
|
detail.StackTrace = fmt.Sprintf("%+v\n", err)
|
|
|
|
}
|
|
|
|
return APIError{
|
|
|
|
StatusCode: fiber.StatusBadRequest,
|
|
|
|
Code: InvalidParam,
|
|
|
|
Message: message,
|
|
|
|
Details: []ErrorDetail{detail},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewInternalError create a new APIError for Internal Errors.
|
|
|
|
func NewInternalError(ctx *fiber.Ctx, err error) APIError {
|
|
|
|
detail := ErrorDetail{
|
|
|
|
RequestID: fmt.Sprintf("%v", ctx.Locals("requestid")),
|
|
|
|
}
|
|
|
|
if enableStackTrace && err != nil {
|
|
|
|
detail.StackTrace = fmt.Sprintf("%+v\n", err)
|
|
|
|
}
|
|
|
|
return APIError{
|
|
|
|
StatusCode: fiber.StatusInternalServerError,
|
|
|
|
Code: Internal,
|
|
|
|
Message: "INTERNAL ERROR",
|
|
|
|
Details: []ErrorDetail{detail},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewNotFoundError create a new APIError for Not Found errors.
|
|
|
|
func NewNotFoundError(ctx *fiber.Ctx) APIError {
|
|
|
|
return APIError{
|
|
|
|
StatusCode: fiber.StatusNotFound,
|
|
|
|
Code: NotFound,
|
|
|
|
Message: "NOT FOUND",
|
|
|
|
Details: []ErrorDetail{{
|
|
|
|
RequestID: fmt.Sprintf("%v", ctx.Locals("requestid")),
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
}
|
2023-01-27 08:47:17 -08:00
|
|
|
|
|
|
|
// NewInvalidQueryParamError create a query param error
|
|
|
|
func NewInvalidQueryParamError(ctx *fiber.Ctx, message string, err error) APIError {
|
|
|
|
if message == "" {
|
|
|
|
message = "INVALID QUERY PARAM"
|
|
|
|
}
|
|
|
|
detail := ErrorDetail{
|
|
|
|
RequestID: fmt.Sprintf("%v", ctx.Locals("requestid")),
|
|
|
|
}
|
|
|
|
if enableStackTrace && err != nil {
|
|
|
|
detail.StackTrace = fmt.Sprintf("%+v\n", err)
|
|
|
|
}
|
|
|
|
return APIError{
|
|
|
|
StatusCode: fiber.StatusBadRequest,
|
|
|
|
Code: InvalidParam,
|
|
|
|
Message: message,
|
|
|
|
Details: []ErrorDetail{detail},
|
|
|
|
}
|
|
|
|
}
|
2023-08-10 07:02:14 -07:00
|
|
|
|
|
|
|
func NewRequestBodyError(ctx *fiber.Ctx, message string, err error) APIError {
|
|
|
|
if message == "" {
|
|
|
|
message = "INVALID BODY"
|
|
|
|
}
|
|
|
|
detail := ErrorDetail{
|
|
|
|
RequestID: fmt.Sprintf("%v", ctx.Locals("requestid")),
|
|
|
|
}
|
|
|
|
if enableStackTrace && err != nil {
|
|
|
|
detail.StackTrace = fmt.Sprintf("%+v\n", err)
|
|
|
|
}
|
|
|
|
return APIError{
|
|
|
|
StatusCode: fiber.StatusBadRequest,
|
|
|
|
Code: InvalidParam,
|
|
|
|
Message: message,
|
|
|
|
Details: []ErrorDetail{detail},
|
|
|
|
}
|
|
|
|
}
|