api: response error in json instead of html for better rendering flexibility

This commit is contained in:
yusing 2025-01-29 11:50:08 +08:00
parent 4ad6257dab
commit d9b6b82f07
3 changed files with 43 additions and 10 deletions

View file

@ -1,10 +1,10 @@
package utils
import (
"encoding/json"
"net/http"
E "github.com/yusing/go-proxy/internal/error"
"github.com/yusing/go-proxy/internal/logging"
"github.com/yusing/go-proxy/internal/utils/strutils/ansi"
)
@ -31,14 +31,13 @@ func RespondError(w http.ResponseWriter, err error, code ...int) {
if len(code) == 0 {
code = []int{http.StatusBadRequest}
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
buf := make([]byte, 0, 100)
errMsg := err.Error()
buf, err = logging.FormatMessageToHTMLBytes(errMsg, buf)
if err != nil {
http.Error(w, ansi.StripANSI(errMsg), code[0])
buf, err := json.Marshal(err)
if err != nil { // just in case
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
http.Error(w, ansi.StripANSI(err.Error()), code[0])
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(code[0])
_, _ = w.Write(buf)
}

View file

@ -1,6 +1,7 @@
package err
import (
"encoding/json"
"errors"
"fmt"
)
@ -46,3 +47,18 @@ func (err baseError) Withf(format string, args ...any) Error {
func (err *baseError) Error() string {
return err.Err.Error()
}
// MarshalJSON implements the json.Marshaler interface.
func (err *baseError) MarshalJSON() ([]byte, error) {
//nolint:errorlint
switch err := err.Err.(type) {
case Error, *withSubject:
return json.Marshal(err)
case json.Marshaler:
return err.MarshalJSON()
case interface{ MarshalText() ([]byte, error) }:
return err.MarshalText()
default:
return json.Marshal(err.Error())
}
}

View file

@ -1,6 +1,7 @@
package err
import (
"encoding/json"
"strings"
"github.com/yusing/go-proxy/internal/utils/strutils/ansi"
@ -8,8 +9,8 @@ import (
//nolint:errname
type withSubject struct {
Subjects []string `json:"subjects"`
Err error `json:"err"`
Subjects []string
Err error
pendingSubject string
}
@ -74,7 +75,7 @@ func (err *withSubject) Error() string {
for _, s := range err.Subjects {
size += len(s)
}
sb.Grow(size + 2 + n*len(subjectSep) + len(errStr))
sb.Grow(size + 2 + n*len(subjectSep) + len(errStr) + len(highlight("")))
for i := n - 1; i > 0; i-- {
sb.WriteString(err.Subjects[i])
@ -85,3 +86,20 @@ func (err *withSubject) Error() string {
sb.WriteString(errStr)
return sb.String()
}
// MarshalJSON implements the json.Marshaler interface.
func (err *withSubject) MarshalJSON() ([]byte, error) {
subjects := make([]string, len(err.Subjects))
for i, s := range err.Subjects {
subjects[len(err.Subjects)-i-1] = s
}
reversed := struct {
Subjects []string `json:"subjects"`
Err error `json:"err"`
}{
Subjects: subjects,
Err: err.Err,
}
return json.Marshal(reversed)
}