fix(t231): expose freight preflight errors

This commit is contained in:
QiuSW
2026-07-29 10:58:28 +08:00
parent 2d8ad97167
commit 5ed27afeb5
15 changed files with 240 additions and 56 deletions
@@ -845,6 +845,18 @@ func writeUsecaseError(ctx *gin.Context, err error) {
case usecase.ErrorKindUnavailable:
status = http.StatusServiceUnavailable
}
switch typed.Code {
case "ERP_NOT_CONFIGURED", "ERP_LOGIN_REJECTED":
status = http.StatusUnprocessableEntity
case "ERP_RESPONSE_INVALID":
status = http.StatusBadGateway
case "OCR_SERVICE_INVALID", "ERP_UNAVAILABLE":
status = http.StatusServiceUnavailable
}
message := typed.Message
if preflightMessage, ok := freightPreflightPublicMessage(typed.Code); ok {
message = preflightMessage
}
details := gin.H{}
if len(typed.Fields) > 0 {
details["fields"] = typed.Fields
@@ -853,12 +865,29 @@ func writeUsecaseError(ctx *gin.Context, err error) {
ctx,
status,
typed.Code,
typed.Message,
message,
typed.Retryable,
details,
)
}
func freightPreflightPublicMessage(code string) (string, bool) {
switch code {
case "ERP_NOT_CONFIGURED":
return "ERP credentials are not configured", true
case "ERP_LOGIN_REJECTED":
return "ERP login was rejected", true
case "ERP_RESPONSE_INVALID":
return "ERP response is invalid", true
case "OCR_SERVICE_INVALID":
return "OCR service is invalid", true
case "ERP_UNAVAILABLE":
return "ERP is temporarily unavailable", true
default:
return "", false
}
}
func writePublicError(
ctx *gin.Context,
status int,
@@ -0,0 +1,46 @@
package httpapi
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"cmroubao/backend-api/internal/usecase"
"github.com/gin-gonic/gin"
)
func TestWriteUsecaseErrorUsesPreflightStatusAndCode(t *testing.T) {
testCases := []struct {
code string
status int
}{
{"ERP_NOT_CONFIGURED", http.StatusUnprocessableEntity},
{"ERP_LOGIN_REJECTED", http.StatusUnprocessableEntity},
{"ERP_RESPONSE_INVALID", http.StatusBadGateway},
{"OCR_SERVICE_INVALID", http.StatusServiceUnavailable},
{"ERP_UNAVAILABLE", http.StatusServiceUnavailable},
}
for _, testCase := range testCases {
t.Run(testCase.code, func(t *testing.T) {
gin.SetMode(gin.TestMode)
router := gin.New()
router.GET("/test", func(ctx *gin.Context) {
writeUsecaseError(ctx, &usecase.Error{
Kind: usecase.ErrorKindUnavailable,
Code: testCase.code,
Message: "private upstream response is hidden",
Fields: map[string]string{},
})
})
response := httptest.NewRecorder()
router.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/test", nil))
if response.Code != testCase.status ||
!strings.Contains(response.Body.String(), testCase.code) ||
strings.Contains(response.Body.String(), "private upstream") {
t.Fatalf("response = %d / %s", response.Code, response.Body)
}
})
}
}