package res
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"github.com/labstack/echo/v5"
"github.com/bangumi/server/web/req/cf"
"github.com/bangumi/server/web/util"
)
var ErrNotFound = NewError(http.StatusNotFound, "resource can't be found in the database or has been removed")
type Error struct {
Title string `json:"title"`
Details any `json:"details,omitempty"`
RequestID string `json:"request_id,omitempty"`
Description string `json:"description"`
}
var _ error = HTTPError{}
type HTTPError struct {
Msg string
Code int
}
func NewError(code int, message string) error {
return HTTPError{Code: code, Msg: message}
}
func (e HTTPError) Error() string {
return strconv.Itoa(e.Code) + ": " + e.Msg
}
func JSONError(c *echo.Context, err error) error {
if ute, ok := err.(*json.UnmarshalTypeError); ok {
return c.JSON(http.StatusBadRequest, Error{
Title: "JSON Error",
Description: fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v",
ute.Type, ute.Value, ute.Field, ute.Offset),
})
}
if se, ok := err.(*json.SyntaxError); ok {
return c.JSON(http.StatusBadRequest, Error{
Title: "JSON Error",
Description: fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error()),
})
}
return c.JSON(http.StatusBadRequest, Error{
Title: "JSON Error",
Description: "can't decode request body as json or value doesn't match expected type",
Details: util.DetailWithErr(c, err),
})
}
func InternalError(c *echo.Context, err error, message string) error {
return c.JSON(http.StatusInternalServerError, Error{
Title: "Internal Server Error",
Description: message,
RequestID: c.Request().Header.Get(cf.HeaderRequestID),
Details: util.DetailWithErr(c, err),
})
}
func BadRequest(message string) error {
return NewError(http.StatusBadRequest, message)
}
func NotFound(message string) error {
return NewError(http.StatusNotFound, message)
}
func Unauthorized(message string) error {
return NewError(http.StatusUnauthorized, message)
}
func Forbidden(message string) error {
return NewError(http.StatusForbidden, message)
}