mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 21:10:51 +08:00
feat(api): return structured JSON error responses
The API error handling is updated to return a structured JSON payload
instead of a plain text message. This provides more context and allows
clients to programmatically handle different error types.
The new error response has the following structure:
{
"error": {
"message": "...",
"type": "..."
}
}
The `type` field is determined by the HTTP status code, such as
`authentication_error`, `rate_limit_error`, or `server_error`.
If the underlying error message from an upstream service is already a
valid JSON string, it will be preserved and returned directly.
BREAKING CHANGE: API error responses are now in a structured JSON
format instead of plain text. Clients expecting plain text error
messages will need to be updated to parse the new JSON body.
This commit is contained in:
@@ -5,6 +5,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -437,12 +438,50 @@ func (h *BaseAPIHandler) WriteErrorResponse(c *gin.Context, msg *interfaces.Erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.Status(status)
|
|
||||||
|
errText := http.StatusText(status)
|
||||||
if msg != nil && msg.Error != nil {
|
if msg != nil && msg.Error != nil {
|
||||||
_, _ = c.Writer.Write([]byte(msg.Error.Error()))
|
if v := strings.TrimSpace(msg.Error.Error()); v != "" {
|
||||||
} else {
|
errText = v
|
||||||
_, _ = c.Writer.Write([]byte(http.StatusText(status)))
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefer preserving upstream JSON error bodies when possible.
|
||||||
|
buildJSONBody := func() []byte {
|
||||||
|
trimmed := strings.TrimSpace(errText)
|
||||||
|
if trimmed != "" && json.Valid([]byte(trimmed)) {
|
||||||
|
return []byte(trimmed)
|
||||||
|
}
|
||||||
|
errType := "invalid_request_error"
|
||||||
|
switch status {
|
||||||
|
case http.StatusUnauthorized:
|
||||||
|
errType = "authentication_error"
|
||||||
|
case http.StatusForbidden:
|
||||||
|
errType = "permission_error"
|
||||||
|
case http.StatusTooManyRequests:
|
||||||
|
errType = "rate_limit_error"
|
||||||
|
default:
|
||||||
|
if status >= http.StatusInternalServerError {
|
||||||
|
errType = "server_error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
payload, err := json.Marshal(ErrorResponse{
|
||||||
|
Error: ErrorDetail{
|
||||||
|
Message: errText,
|
||||||
|
Type: errType,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return []byte(fmt.Sprintf(`{"error":{"message":%q,"type":"server_error"}}`, errText))
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Writer.Written() {
|
||||||
|
c.Writer.Header().Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
c.Status(status)
|
||||||
|
_, _ = c.Writer.Write(buildJSONBody())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *BaseAPIHandler) LoggingAPIResponseError(ctx context.Context, err *interfaces.ErrorMessage) {
|
func (h *BaseAPIHandler) LoggingAPIResponseError(ctx context.Context, err *interfaces.ErrorMessage) {
|
||||||
|
|||||||
Reference in New Issue
Block a user