OpenAPI: type object fields as an open map, not an empty object
#24
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
AdminObjectView.fields(and the analogous flexible-field maps onPublicViewand theObjectCreateRequest/set_fieldsrequest body) are annotated on the Rust side with#[schema(value_type = Object)]. utoipa emits that as a bare{"type":"object"}with noadditionalProperties, whichopenapi-typescriptnarrows toRecord<string, never>— i.e. the generated TS type says the object can have no keys.This surfaced while building the frontend SPA (milestone 1): the object-detail view must read flexible field values out of
fields, but the generated type makes that impossible without a cast. The interim workaround in the web client isObject.entries(object.fields as Record<string, unknown>)inweb/src/objects/object-detail.tsx, plus test fixtures that returnfieldsas plain object literals.What to do
Annotate the flexible-field maps so the OpenAPI document describes an open string→any map (
additionalPropertiespresent), soopenapi-typescriptgenerates{ [key: string]: unknown }/Record<string, unknown>instead ofRecord<string, never>. Likely options in utoipa: use#[schema(value_type = HashMap<String, serde_json::Value>)](or an equivalent that yieldsadditionalProperties) on thefieldsfield ofAdminObjectView,PublicView, and any request DTO carrying a free-form field map. Verify the emitted schema hasadditionalPropertiesand regenerateweb/src/api/schema.d.ts.Acceptance
fieldsas an object withadditionalProperties(not an empty closed object).schema.d.tstypesfieldsas an open map; theas Record<string, unknown>cast inobject-detail.tsx(and any fixture workarounds) can be removed.Source: frontend SPA milestone 1 implementation (the typed client consumes this contract).