API: Align i18n.Response Go field names with JSON keys #5682

Rename the Response struct fields to match their json tags (Err to Error, Msg to Message) and the Error() method to ErrorString() to avoid a field/method clash; update callers and tests. JSON wire format is unchanged.
This commit is contained in:
Michael Mayer 2026-06-23 12:42:57 +00:00
parent fd8448d6de
commit c5658a053d
8 changed files with 42 additions and 38 deletions

View file

@ -216,7 +216,7 @@ func TestBatchLabelsDelete(t *testing.T) {
}
assert.True(t, resp.Success())
assert.Equal(t, i18n.Msg(i18n.MsgLabelsDeleted), resp.Msg)
assert.Equal(t, i18n.Msg(i18n.MsgLabelsDeleted), resp.Message)
assert.Equal(t, i18n.Msg(i18n.MsgLabelsDeleted), resp.String())
assert.Equal(t, http.StatusOK, r2.Code)
assert.Equal(t, http.StatusOK, resp.Code)

View file

@ -188,7 +188,7 @@ func StartImport(router *gin.RouterGroup) {
log.Warnf("index: %s (update covers)", err)
}
c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Msg: msg})
c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Message: msg})
})
}

View file

@ -23,7 +23,7 @@ func TestCancelImport(t *testing.T) {
}
assert.True(t, resp.Success())
assert.Equal(t, i18n.Msg(i18n.MsgImportCanceled), resp.Msg)
assert.Equal(t, i18n.Msg(i18n.MsgImportCanceled), resp.Message)
assert.Equal(t, i18n.Msg(i18n.MsgImportCanceled), resp.String())
assert.Equal(t, http.StatusOK, r.Code)
assert.Equal(t, http.StatusOK, resp.Code)

View file

@ -195,7 +195,7 @@ func StartIndexing(router *gin.RouterGroup) {
UpdateClientConfig()
c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Msg: msg})
c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Message: msg})
})
}

View file

@ -25,7 +25,7 @@ func TestCancelIndex(t *testing.T) {
}
assert.True(t, resp.Success())
assert.Equal(t, i18n.Msg(i18n.MsgIndexingCanceled), resp.Msg)
assert.Equal(t, i18n.Msg(i18n.MsgIndexingCanceled), resp.Message)
assert.Equal(t, i18n.Msg(i18n.MsgIndexingCanceled), resp.String())
assert.Equal(t, http.StatusOK, r.Code)
assert.Equal(t, http.StatusOK, resp.Code)

View file

@ -259,7 +259,7 @@ func UploadUserFiles(router *gin.RouterGroup) {
log.Info(msg)
c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Msg: msg})
c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Message: msg})
})
}
@ -420,6 +420,6 @@ func ProcessUserUpload(router *gin.RouterGroup) {
log.Warnf("upload: %s (update covers)", coversErr)
}
c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Msg: msg})
c.JSON(http.StatusOK, i18n.Response{Code: http.StatusOK, Message: msg})
})
}

View file

@ -4,24 +4,25 @@ import "strings"
// Response represents an i18n-aware response payload.
//
// Err/Msg carry the server-rendered string in the instance locale (a fallback for non-browser
// Error/Message carry the server-rendered string in the instance locale (a fallback for non-browser
// consumers); MessageID and MessageParams carry the untranslated source string and its parameters
// so the Web UI can render the message in each user's current UI locale.
type Response struct {
Code int `json:"code"`
Err string `json:"error,omitempty"`
Msg string `json:"message,omitempty"`
Error string `json:"error,omitempty"`
Message string `json:"message,omitempty"`
MessageID string `json:"messageId,omitempty"`
MessageParams []any `json:"messageParams,omitempty"`
Details string `json:"details,omitempty"`
}
// String returns the response message as string.
func (r Response) String() string {
if r.Err != "" {
return r.Err
} else {
return r.Msg
if r.Error != "" {
return r.Error
}
return r.Message
}
// LowerString returns the lowercased message string.
@ -29,24 +30,27 @@ func (r Response) LowerString() string {
return strings.ToLower(r.String())
}
func (r Response) Error() string {
return r.Err
// ErrorString returns the error message as string.
func (r Response) ErrorString() string {
return r.Error
}
// Success reports whether the response code indicates success (2xx).
func (r Response) Success() bool {
return r.Err == "" && r.Code < 400
return r.Error == "" && r.Code < 400
}
// NewResponse builds a Response with the given code, message ID, and optional parameters.
// It carries the untranslated source string (ID) and Params so the frontend can render the message
// in the current UI locale, in addition to the server-rendered Err/Msg fallback.
// It carries the untranslated source string (MessageID) and MessageParams so the frontend can render
// the message in the current UI locale, in addition to the server-rendered Error/Message fallback.
func NewResponse(code int, id Message, params ...any) Response {
r := Response{Code: code, MessageID: Source(id), MessageParams: params}
if code < 400 {
r.Msg = Msg(id, params...)
r.Message = Msg(id, params...)
} else {
r.Err = Msg(id, params...)
r.Error = Msg(id, params...)
}
return r
}

View file

@ -12,23 +12,23 @@ func TestNewResponse(t *testing.T) {
t.Run("AlreadyExists", func(t *testing.T) {
resp := NewResponse(http.StatusConflict, ErrAlreadyExists, "A cat")
assert.Equal(t, http.StatusConflict, resp.Code)
assert.Equal(t, "A cat already exists", resp.Err)
assert.Equal(t, "", resp.Msg)
assert.Equal(t, "A cat already exists", resp.Error)
assert.Equal(t, "", resp.Message)
assert.Equal(t, "%s already exists", resp.MessageID)
assert.Equal(t, []any{"A cat"}, resp.MessageParams)
})
t.Run("UnexpectedError", func(t *testing.T) {
resp := NewResponse(http.StatusInternalServerError, ErrUnexpected, "A cat")
assert.Equal(t, http.StatusInternalServerError, resp.Code)
assert.Equal(t, "Something went wrong, try again", resp.Err)
assert.Equal(t, "", resp.Msg)
assert.Equal(t, "Something went wrong, try again", resp.Error)
assert.Equal(t, "", resp.Message)
assert.Equal(t, "Something went wrong, try again", resp.MessageID)
})
t.Run("ChangesSaved", func(t *testing.T) {
resp := NewResponse(http.StatusOK, MsgChangesSaved)
assert.Equal(t, http.StatusOK, resp.Code)
assert.Equal(t, "", resp.Err)
assert.Equal(t, "Changes successfully saved", resp.Msg)
assert.Equal(t, "", resp.Error)
assert.Equal(t, "Changes successfully saved", resp.Message)
assert.Equal(t, "Changes successfully saved", resp.MessageID)
if s, err := json.Marshal(resp); err != nil {
@ -41,12 +41,12 @@ func TestNewResponse(t *testing.T) {
func TestResponse_String(t *testing.T) {
t.Run("Error", func(t *testing.T) {
resp := Response{Code: 404, Err: "Not found", Msg: "page not found", Details: "xyz"}
resp := Response{Code: 404, Error: "Not found", Message: "page not found", Details: "xyz"}
assert.Equal(t, "Not found", resp.String())
})
t.Run("NoError", func(t *testing.T) {
t.Run("Error", func(t *testing.T) {
resp := Response{Code: 200, Msg: "Ok", Details: "xyz"}
resp := Response{Code: 200, Message: "Ok", Details: "xyz"}
assert.Equal(t, "Ok", resp.String())
})
})
@ -54,38 +54,38 @@ func TestResponse_String(t *testing.T) {
func TestResponse_LowerString(t *testing.T) {
t.Run("Error", func(t *testing.T) {
resp := Response{Code: 404, Err: "Not found", Msg: "page not found", Details: "xyz"}
resp := Response{Code: 404, Error: "Not found", Message: "page not found", Details: "xyz"}
assert.Equal(t, "not found", resp.LowerString())
})
t.Run("NoError", func(t *testing.T) {
t.Run("Error", func(t *testing.T) {
resp := Response{Code: 200, Msg: "Ok", Details: "xyz"}
resp := Response{Code: 200, Message: "Ok", Details: "xyz"}
assert.Equal(t, "ok", resp.LowerString())
})
})
}
func TestResponse_Error(t *testing.T) {
func TestResponse_ErrorString(t *testing.T) {
t.Run("Error", func(t *testing.T) {
resp := Response{Code: 404, Err: "Not found", Msg: "page not found", Details: "xyz"}
assert.Equal(t, "Not found", resp.Error())
resp := Response{Code: 404, Error: "Not found", Message: "page not found", Details: "xyz"}
assert.Equal(t, "Not found", resp.ErrorString())
})
t.Run("NoError", func(t *testing.T) {
t.Run("Error", func(t *testing.T) {
resp := Response{Code: 200, Msg: "Ok", Details: "xyz"}
assert.Equal(t, "", resp.Error())
resp := Response{Code: 200, Message: "Ok", Details: "xyz"}
assert.Equal(t, "", resp.ErrorString())
})
})
}
func TestResponse_Success(t *testing.T) {
t.Run("Error", func(t *testing.T) {
resp := Response{Code: 404, Err: "Not found", Msg: "page not found", Details: "xyz"}
resp := Response{Code: 404, Error: "Not found", Message: "page not found", Details: "xyz"}
assert.Equal(t, false, resp.Success())
})
t.Run("NoError", func(t *testing.T) {
t.Run("Error", func(t *testing.T) {
resp := Response{Code: 200, Msg: "Ok", Details: "xyz"}
resp := Response{Code: 200, Message: "Ok", Details: "xyz"}
assert.Equal(t, true, resp.Success())
})
})