[refactor](alarm): make a readable message structural on every error
An error status with an empty body is a client-breaking bug that review does not reliably catch. Route every JSON and plain-text error through internal/apierr, which substitutes the code canonical message when a caller supplies none, and keep the frozen codes in one package shared by the action and WebSocket layers.
This commit is contained in:
+14
-32
@@ -31,7 +31,6 @@ import (
|
||||
"time"
|
||||
|
||||
"git.dcntrlized.org/Dcntrlized/Alarm/db"
|
||||
"git.dcntrlized.org/Dcntrlized/Alarm/internal/alertstate"
|
||||
"git.dcntrlized.org/Dcntrlized/Alarm/internal/apierr"
|
||||
"git.dcntrlized.org/dcntrlized/dcntrlized-auth/authclient"
|
||||
"github.com/google/uuid"
|
||||
@@ -40,15 +39,16 @@ import (
|
||||
// Frozen v1 error codes, aliased from internal/apierr so the WebSocket layer
|
||||
// (which cannot import this package) uses the same strings.
|
||||
const (
|
||||
CodeAlertNotFound = apierr.AlertNotFound
|
||||
CodeAlertTokenInvalid = apierr.AlertTokenInvalid
|
||||
CodeAlertNotAdmin = apierr.AlertNotAdmin
|
||||
CodeAlertAlreadyJoined = apierr.AlertAlreadyJoined
|
||||
CodeAlertNotSubscribed = apierr.AlertNotSubscribed
|
||||
CodeAlertState = apierr.AlertState
|
||||
CodeValidation = apierr.Validation
|
||||
CodeUnauthorized = apierr.Unauthorized
|
||||
CodeInternal = apierr.Internal
|
||||
CodeAlertNotFound = apierr.AlertNotFound
|
||||
CodeAlertTokenInvalid = apierr.AlertTokenInvalid
|
||||
CodeAlertNotAdmin = apierr.AlertNotAdmin
|
||||
CodeAlertAlreadyJoined = apierr.AlertAlreadyJoined
|
||||
CodeAlertNotSubscribed = apierr.AlertNotSubscribed
|
||||
CodeAlertState = apierr.AlertState
|
||||
CodeAlarmTriggeredOffline = apierr.AlarmTriggeredOffline
|
||||
CodeValidation = apierr.Validation
|
||||
CodeUnauthorized = apierr.Unauthorized
|
||||
CodeInternal = apierr.Internal
|
||||
)
|
||||
|
||||
// maxMessageBytes / maxNameChars bound the free-text fields.
|
||||
@@ -60,22 +60,11 @@ const (
|
||||
maxPlatformLen = 32
|
||||
)
|
||||
|
||||
// errorEnvelope is the platform error body.
|
||||
type errorEnvelope struct {
|
||||
Error struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
} `json:"error"`
|
||||
}
|
||||
|
||||
// writeError emits {"error":{"code","message"}}.
|
||||
// writeError emits {"error":{"code","message"}}. It delegates to apierr.Write,
|
||||
// which guarantees both fields are non-empty: this package can pass a literal
|
||||
// message, but the invariant is enforced centrally (see internal/apierr).
|
||||
func writeError(w http.ResponseWriter, status int, code, message string) {
|
||||
var body errorEnvelope
|
||||
body.Error.Code = code
|
||||
body.Error.Message = message
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
_ = json.NewEncoder(w).Encode(body)
|
||||
apierr.Write(w, status, code, message)
|
||||
}
|
||||
|
||||
// writeJSON emits a success body.
|
||||
@@ -180,13 +169,6 @@ func validateMessage(raw string) (string, error) {
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func validateAutoStop(seconds int) error {
|
||||
if seconds < 0 || seconds > alertstate.MaxAutoStopSeconds {
|
||||
return fmt.Errorf("autoStopSeconds must be between 0 and %d", alertstate.MaxAutoStopSeconds)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateDeviceID(raw string) (string, error) {
|
||||
id := strings.TrimSpace(raw)
|
||||
if id == "" {
|
||||
|
||||
Reference in New Issue
Block a user