Result box: color-code by status + friendly error messages from error codes (#105)
CI / test (push) Successful in 23s
CI / docker (push) Skipped

- Backend create/can validation paths emit machine-readable error codes
  (slug_taken, slug_invalid, content_empty, content_too_large,
  expiry_invalid, rate_limited, ...) alongside the human message
- new.html JS maps codes to plain-language guidance with generic fallback
- Result card colored via --ok/--err/--warn left border (result-ok/err/warn)
- docs/API.md error section documents the code field
- Tests assert the code on every validation path
This commit is contained in:
2026-09-09 17:28:25 -05:00
parent c35531e03e
commit 9df6224a27
7 changed files with 216 additions and 18 deletions
+5 -5
View File
@@ -28,7 +28,7 @@ func (a *apiServer) handleCreateCan(w http.ResponseWriter, r *http.Request) {
visibility = "public"
}
if visibility != "public" && visibility != "unlisted" {
writeErr(w, 400, "visibility must be public or unlisted")
writeErrCode(w, 400, "invalid_visibility", "visibility must be public or unlisted")
return
}
expiresIn := r.FormValue("expires_in")
@@ -40,13 +40,13 @@ func (a *apiServer) handleCreateCan(w http.ResponseWriter, r *http.Request) {
if expiresIn != "" {
d, err := time.ParseDuration(expiresIn)
if err != nil {
writeErr(w, 400, "invalid expires_in")
writeErrCode(w, 400, "expiry_invalid", "invalid expires_in")
return
}
// #60/#48: clamp at the API boundary like the pastes API does -
// reject zero/negative and durations past the 1-year UI cap.
if !store.ValidExpiry(d) {
writeErr(w, 400, "expires_in must be between 1 minute and 1 year")
writeErrCode(w, 400, "expiry_invalid", "expires_in must be between 1 minute and 1 year")
return
}
t := now + int64(d.Seconds())
@@ -71,7 +71,7 @@ func (a *apiServer) handleCreateCan(w http.ResponseWriter, r *http.Request) {
if err != nil {
switch err {
case store.ErrSlugTaken, store.ErrInvalidSlug, store.ErrReservedSlug:
writeErr(w, 409, err.Error())
writeErrCode(w, 409, createErrCode(err), err.Error())
default:
writeErr(w, 500, "db error")
}
@@ -137,7 +137,7 @@ func (a *apiServer) handleCreateCan(w http.ResponseWriter, r *http.Request) {
if itemCount == 0 {
a.store.DeleteCan(canID)
writeErr(w, 400, "can needs at least one item (files or json_items)")
writeErrCode(w, 400, "content_empty", "can needs at least one item (files or json_items)")
return
}