{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"\u2699\ufe0f react-openapi \u2014 Spec-driven Admin UI","text":"
react-openapi turns an OpenAPI 3.1 document into a complete CRUD admin at runtime: list, detail, create/edit, filtering, foreign-key selects, streaming views and profile screens. Nothing per-resource is hand-written \u2014 the paths and schemas, plus a small set of x- extensions, are the single source of truth.
Doc model: this wiki is written for humans \u2014 architecture, the extension catalogue, and UI recipes. The authoritative API contracts live in the code (RDFC JSDoc) and the machine-readable bundle under docs/mcp/. Browse the TypeDoc site for the full symbol reference.
ResourceConfig per collection, routes, filter widgets, FK options and form/validation wiringx- extensions as the contract \u2014 display formats, list columns, hidden fields, ordering, FKs, uploads, SSE, profile and auth endpointsFieldConfig resolves to the right MUI control (select, switch, date picker, upload, chips, FK autocomplete)x-sse resources render as live streams with reactive connection statusgetToken callback, plus auth endpoints derived from securitySchemesx- extension, its level and its validator rule Admin UI Components, hooks, field renderers, SSE and auth"},{"location":"#quick-start","title":"\ud83d\ude80 Quick Start","text":"import { AppProvider, Admin } from \"react-openapi\";\n\n<AppProvider specConfiguration={{ specUrl: \"/openapi.json\" }}>\n <Admin basePath=\"/admin\" />\n</AppProvider>\n Requires React 18, React Router and MUI (peer dependencies). Admin and ProfileRoutes must be nested inside an AppProvider and a router.
react-openapi repository (README.md carries the full spec-authoring guide)lib HTML for the full API referencedocs/mcp/ (docs://modules/react-openapi)react-openapi (MCP :8012)securitySchemes.bearerAuth \u2014 read docs://spec on the standards MCP:8013)\u00a9 Aetoskia Internal \u2014 react-openapi 0.0.1
react-openapi is a compiler that runs in the browser: it reads an OpenAPI document, validates it, transforms it into an internal resource model, and renders UI from that model. It never edits your spec, and it never falls back silently when a required extension is missing.
OpenAPI document (runtime fetch)\n |\n spec-loader -> parsed spec object\n |\n spec-validator -> errors / warnings / info messages\n |\n transformers -> ResourceConfig[] + FieldConfig[] + relationships\n |\n AppProvider -> AppContext (resources, schemas, auth, api client)\n |\n Admin / renderers -> routes, tables, forms, streams\n Layer Module Responsibility Load spec-loader.ts fetch JSON/YAML, resolve $ref Validate spec-validator.ts error / warning / info rules Transform transformers/* schema \u2192 ResourceConfig, properties \u2192 FieldConfig State context/AppProvider.tsx, AppContext shared resources, schemas, auth, axios client HTTP hooks/useApi.ts initApi, getApi with bearer injection Present components/* Admin, ResourceList/Detail/Form, renderers"},{"location":"01_overview/#quick-start","title":"\ud83d\udce6 Quick start","text":"import { AppProvider, Admin } from \"react-openapi\";\nimport type { SpecConfiguration } from \"react-openapi\";\n\nconst specConfiguration: SpecConfiguration = {\n specUrl: \"/api/openapi.yaml\",\n baseApiUrl: \"https://api.example.com/v1\",\n title: \"Vet Clinic Admin\",\n getToken: () => localStorage.getItem(\"token\"),\n};\n\nexport default function App() {\n return (\n <AppProvider specConfiguration={specConfiguration}>\n <Admin basePath=\"/admin\" />\n </AppProvider>\n );\n}\n Admin renders SideMenu plus nested routes per resource: /<basePath>/<resource> (list), /<resource>/new, /<resource>/:id (detail), /<resource>/:id/edit. Streaming (x-sse) resources render only the list.
specValidator runs over it.x-resource becomes a ResourceConfig (name, schemaName, displayName, path, streaming, pagination).FieldConfig \u2014 x-order, x-label, x-hidden, x-filterable, x-sortable, x-edit-as, x-ui-type.useResource(name) adds CRUD helpers (list, get, create, update, remove, stream?) for one resource.ListCellRenderer / DetailFieldRenderer / FormFieldRenderer dispatch to the concrete control for that FieldConfig.x-resource must equal the path segment. No pluralisation guessing.x-primary-key, x-display-format, x-list-columns, x-label or x-order fails at transform time rather than defaulting silently.{ total?, items[] }, non-paginated lists are a plain array. No fallback chains.?limit=0 on paginated targets: a server convention meaning \"return all\", not documented in the spec.react-openapi is configured entirely by x- extensions inside the OpenAPI document. This page is the catalogue; the repository README.md carries the complete authoring guide with a minimal worked spec.
Validation levels \u2014 error (the admin will not render), warning (renders, shown in a snackbar), info (informational note).
x-resource \u2705 Marks the schema as a resource; value must equal the collection path segment (pets \u2192 /pets). Schemas without it are skipped entirely (use for ErrorBody, Metadata, \u2026). x-primary-key \u2705 Property used as the :id path parameter. Must exist in properties. x-display-format \u2705 Template such as \"{name} - #{id}\"; used for row labels, detail titles and FK options. x-list-columns \u2705 Ordered property names for the datatable; every entry must exist."},{"location":"02_spec_extensions/#property-level","title":"\ud83d\udce6 Property level","text":"Extension Required Purpose x-label \u2705 Label for form field, table header and detail view. x-order \u2705 Field ordering; ties break alphabetically. x-description \u2014 Helper text / placeholder; falls back to x-label. x-hidden \u2014 { form, list, detail } visibility; missing keys default to false. x-filterable \u2014 Marks the field filterable (UI integration reserved). x-sortable \u2014 Sends ?sort=field / ?sort=-field on the list endpoint. x-edit-as \u2014 e.g. date \u2014 edit a date-time field with a date input. x-fk \u2014 { resource, prefetch } \u2014 render a dropdown or multi-select for a $ref. x-ui-type \u2014 image \u2014 file/image upload control. x-upload / x-upload-url \u2014 Raw-binary upload (type: image\\|pdf\\|html\\|csv\\|file) or an image POST endpoint with {id}."},{"location":"02_spec_extensions/#foreign-keys","title":"Foreign keys","text":"owner:\n $ref: '#/components/schemas/Parent'\n x-fk:\n resource: parents # the target's x-resource value, not the schema name\n prefetch: true # false -> load options on focus\n $ref \u2192 FkSelectField dropdown; type: array \u2192 FkMultiSelectField.GET /{target}?limit=0 (paginated) or GET /{target}, then formatted with the target's x-display-format.resource must match some x-resource, and that target must have x-display-format + x-primary-key.$ref without x-fk renders read-only (InlineRefField chips, or a disabled JSON text field in forms) and emits an info message.x-sse Marks a path as a Server-Sent Events stream instead of REST CRUD. /pets/events:\n x-sse: true\n get:\n summary: Subscribe to Pet events\n responses:\n 200:\n description: SSE stream of Pet change events\n content:\n text/event-stream:\n schema: { type: object }\n An x-sse resource is excluded from the sidebar, list/detail routes and CRUD hooks \u2014 it appears only in the streaming collection and is reachable through useResource(name).stream / SseStreamView.
Derived from components.securitySchemes.bearerAuth:
x-server-url Auth server base URL \u2192 AuthConfig.serverUrl x-login-path \u2192 loginPath x-register-path \u2192 registerPath x-logout-path \u2192 logoutPath x-me-path \u2192 mePath x-introspect-path \u2192 introspectPath Requests carry Authorization: Bearer <token> from SpecConfiguration.getToken. On a 401 the stored token is cleared so a refresh flow can take over.
x-profile)","text":"x-profile operations describe the current-user view/edit/create screens. SpecConfiguration.profileComponents supplies React components for them, and they are mounted through the exported ProfileRoutes.
For each schema with x-resource:
x-primary-key, x-display-format, x-list-columns present and valid.x-label and x-order.$ref without x-fk \u2192 info; x-fk target must exist and be displayable.x-resource path exists with GET + POST./{resource}/{id} exists with GET + PUT + DELETE.limit must carry a schema.default.Everything on screen comes from the loaded spec. This page lists the pieces you compose with, and the three ways to override the generated behaviour.
"},{"location":"03_admin_ui/#components","title":"\ud83d\udce6 Components","text":"Export PurposeAppProvider Loads and validates the spec, builds resource configs, initialises the axios client, provides context. Wrap the app with it. Admin Sidebar + nested routes for every resource. Takes basePath. ProfileRoutes Routes for x-profile view/edit/create operations. ListCellRenderer One list/table cell; honours FK display formats, inline refs, enums, booleans. DetailFieldRenderer Read-only label + value pair in the detail view. FormFieldRenderer Editable form field; dispatches to the concrete control. FilterBar / SideMenu / Layout Layout primitives used by Admin. ValidationAlert Spec validation errors/warnings surface. SseStreamView Live stream card: status, event counter, latest event, snackbar. SseConnectionStatus Green/red dot with Connected/Disconnected \u2014 reactive everywhere. MultiEnumField, CurrencyField, FkMultiSelectField Exported controls you can reuse in custom screens."},{"location":"03_admin_ui/#field-renderer-dispatch","title":"Field renderer dispatch","text":"Condition Form control List / detail x-fk, not an array FkSelectField display-format cell x-fk, type: array FkMultiSelectField chips enum EnumField chip type: boolean BooleanField (switch) Yes/No chip type: integer / number NumberField typography format: date / date-time DateField typography x-ui-type: image / x-upload upload control avatar / chip $ref without x-fk disabled JSON field InlineRefField chips otherwise StringField typography"},{"location":"03_admin_ui/#hooks","title":"\ud83d\udce6 Hooks","text":"const { config, resources, schemas, loading, errors, warnings } = useAppContext();\n\nconst { resource, components, list, get, create, update, remove, stream, loading, error } =\n useResource(\"pets\");\n useAppContext() \u2014 the whole derived model.useResource(name) \u2014 CRUD + optional stream(handlers, pathParams?) \u2192 { close } for x-sse resources; components holds the per-resource filter widgets.useItemSse(url, handlers) \u2014 subscribe to one item's event stream.useFkFieldOptions(...) / getApi() \u2014 FK options and the configured axios instance for custom calls.sanitizePayload(payload, resolver) \u2014 strips/normalises fields before create/update.specConfiguration.resourceConfig","text":"<AppProvider specConfiguration={{\n specUrl: \"/api/openapi.yaml\",\n resourceConfig: {\n invoices: { filterOptions: { mode: \"sidebar\" }, fieldTypes: { amount: \"currency\" } },\n },\n}} />\n"},{"location":"03_admin_ui/#2-profile-screens-specconfigurationprofilecomponents","title":"2. Profile screens \u2014 specConfiguration.profileComponents","text":"<AppProvider specConfiguration={{\n specUrl: \"/api/openapi.yaml\",\n profileComponents: { view: ProfileView, edit: ProfileEdit, create: ProfileCreate },\n}} />\n"},{"location":"03_admin_ui/#3-your-own-screens-hooks","title":"3. Your own screens \u2014 hooks","text":"import { useAppContext, SseStreamView } from \"react-openapi\";\n\nfunction MyStreamPage() {\n const { resources } = useAppContext();\n const res = resources.find((r) => r.name === \"calls\");\n if (!res) return null;\n return <SseStreamView resource={res} />;\n}\n"},{"location":"03_admin_ui/#streaming","title":"\ud83d\udce1 Streaming","text":"useResource(\"calls\").stream({ onEvent, onError, onOpen }) returns a subscription with close(). Reconnection is browser-native; components read connection state from SseConnectionStatus.
getToken is called per request and injected as Authorization: Bearer. Auth endpoints are derived from the spec's securitySchemes.bearerAuth extensions (see Spec Extensions).
Combine with react-auth
react-auth owns the login/register UI and the session; react-openapi only needs a token. Feed getToken: tokenStore.get into specConfiguration to share one session between the two.