Type enum-valued fields (visibility, data_type, authority kind) as enums in OpenAPI #29

Closed
opened 2026-06-04 06:46:49 +00:00 by logaritmisk · 0 comments
Owner

Context

Several enum-valued fields are emitted in the OpenAPI document as bare string, so the generated TypeScript client (web/src/api/schema.d.ts) types them as string rather than a literal union. The frontend then carries as-casts to the real union at each use site:

  • AdminObjectView.visibility / PublicView.visibilitystring. Cast as Visibility in web/src/objects/visibility-badge.tsx, object-detail.tsx, and publish-control.tsx (milestones 1 & 3).
  • FieldDefinitionView.data_typestring (the frontend switches on it in field-input.tsx).
  • AuthorityView.kind / FieldDefinitionView.authority_kindstring.

These are almost certainly annotated #[schema(value_type = String)] (or similar) on the Rust side, which flattens the enum to a string in the schema.

What to do

Where the Rust enum is a fixed, closed set (Visibility = draft/internal/public; FieldType's data_type tag; AuthorityKind = person/organisation/place), let utoipa emit a proper string enum (e.g. derive ToSchema on the enum so the schema lists the allowed values) instead of a bare string. Then regenerate web/src/api/schema.d.ts — the generated types become literal unions and the frontend as Visibility / data_type casts can be removed.

Acceptance

  • The OpenAPI JSON lists the allowed values for visibility, data_type, and authority kind (string enums).
  • Regenerated schema.d.ts types them as unions; the frontend casts drop; web typecheck/tests stay green.

References

  • Rust DTOs: crates/api/src/admin_objects.rs, admin_authorities.rs, public.rs; domain::{Visibility, FieldType, AuthorityKind} (all have as_str/from_db + serde lowercase).
  • Frontend cast sites listed above.
  • Sibling of #24 (free-form fields map typing). Both are "tighten the generated client contract" cleanups.
## Context Several enum-valued fields are emitted in the OpenAPI document as bare `string`, so the generated TypeScript client (`web/src/api/schema.d.ts`) types them as `string` rather than a literal union. The frontend then carries `as`-casts to the real union at each use site: - `AdminObjectView.visibility` / `PublicView.visibility` → `string`. Cast `as Visibility` in `web/src/objects/visibility-badge.tsx`, `object-detail.tsx`, and `publish-control.tsx` (milestones 1 & 3). - `FieldDefinitionView.data_type` → `string` (the frontend switches on it in `field-input.tsx`). - `AuthorityView.kind` / `FieldDefinitionView.authority_kind` → `string`. These are almost certainly annotated `#[schema(value_type = String)]` (or similar) on the Rust side, which flattens the enum to a string in the schema. ## What to do Where the Rust enum is a fixed, closed set (`Visibility` = draft/internal/public; `FieldType`'s data_type tag; `AuthorityKind` = person/organisation/place), let utoipa emit a proper string **enum** (e.g. derive `ToSchema` on the enum so the schema lists the allowed values) instead of a bare `string`. Then regenerate `web/src/api/schema.d.ts` — the generated types become literal unions and the frontend `as Visibility` / `data_type` casts can be removed. ## Acceptance - The OpenAPI JSON lists the allowed values for `visibility`, `data_type`, and authority `kind` (string enums). - Regenerated `schema.d.ts` types them as unions; the frontend casts drop; web typecheck/tests stay green. ## References - Rust DTOs: `crates/api/src/admin_objects.rs`, `admin_authorities.rs`, `public.rs`; `domain::{Visibility, FieldType, AuthorityKind}` (all have `as_str`/`from_db` + serde lowercase). - Frontend cast sites listed above. - Sibling of #24 (free-form `fields` map typing). Both are "tighten the generated client contract" cleanups.
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#29