set_object_fields 422 should carry field-level detail (so the UI can highlight the offending field) #28

Closed
opened 2026-06-04 05:24:00 +00:00 by logaritmisk · 0 comments
Owner

Context

PUT /api/admin/objects/{id}/fields returns a bare 422 on UnknownField / TypeMismatch / Unresolved (the admin handler maps all three FieldError variants to StatusCode::UNPROCESSABLE_ENTITY with no body — crates/api/src/admin_objects.rs). The db layer's FieldError actually carries the offending field key + reason, but that detail is dropped at the HTTP boundary.

Consequence for the frontend (object authoring, milestone 2): when a field write is rejected, the form can only show a generic form-level "the server rejected the changes" banner (form.rejected) — it cannot highlight which flexible field was wrong. Client-side validation catches required/empty cases, but type/reference mismatches that only the server knows about surface as an opaque 422.

This also affects the publish gate's MissingRequiredFields (issue #16 closed) and any other admin validation 422 — they're all bare today.

What to do

  • Return a structured 422 body from set_fields (and consider the other admin validation 422s) carrying the field key(s) + error kind, e.g. { "errors": [{ "field": "material", "kind": "unresolved" }] }. Add the schema to OpenAPI so it's typed on the client.
  • Frontend: map the structured errors onto the specific FieldInputs (per-field error messages) instead of the generic banner.

References

  • crates/api/src/admin_objects.rsset_fields handler (the FieldError → 422 mapping)
  • crates/db/src/catalog.rsFieldError { UnknownField(String), TypeMismatch{field,expected}, Unresolved{field,kind}, .. } (already carries detail)
  • web/src/objects/object-form.tsx / object-new-page.tsx / object-edit-form.tsx (currently show form.rejected)
  • Noted in the M2 design follow-ups.
## Context `PUT /api/admin/objects/{id}/fields` returns a **bare 422** on `UnknownField` / `TypeMismatch` / `Unresolved` (the admin handler maps all three `FieldError` variants to `StatusCode::UNPROCESSABLE_ENTITY` with no body — `crates/api/src/admin_objects.rs`). The `db` layer's `FieldError` actually carries the offending field key + reason, but that detail is dropped at the HTTP boundary. Consequence for the frontend (object authoring, milestone 2): when a field write is rejected, the form can only show a generic form-level "the server rejected the changes" banner (`form.rejected`) — it cannot highlight *which* flexible field was wrong. Client-side validation catches required/empty cases, but type/reference mismatches that only the server knows about surface as an opaque 422. This also affects the publish gate's `MissingRequiredFields` (issue #16 closed) and any other admin validation 422 — they're all bare today. ## What to do - Return a structured 422 body from `set_fields` (and consider the other admin validation 422s) carrying the field key(s) + error kind, e.g. `{ "errors": [{ "field": "material", "kind": "unresolved" }] }`. Add the schema to OpenAPI so it's typed on the client. - Frontend: map the structured errors onto the specific `FieldInput`s (per-field error messages) instead of the generic banner. ## References - `crates/api/src/admin_objects.rs` — `set_fields` handler (the `FieldError` → 422 mapping) - `crates/db/src/catalog.rs` — `FieldError { UnknownField(String), TypeMismatch{field,expected}, Unresolved{field,kind}, .. }` (already carries detail) - `web/src/objects/object-form.tsx` / `object-new-page.tsx` / `object-edit-form.tsx` (currently show `form.rejected`) - Noted in the M2 design follow-ups.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logaritmisk/biggus-dickus#28