{"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.

"},{"location":"#key-features","title":"\ud83d\ude80 Key Features","text":""},{"location":"#documentation-structure","title":"\ud83d\udce6 Documentation Structure","text":"Section Description Overview Architecture, data flow and quick start Spec Extensions Every x- 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.

"},{"location":"#related-resources","title":"\ud83d\udd17 Related Resources","text":"

\u00a9 Aetoskia Internal \u2014 react-openapi 0.0.1

"},{"location":"01_overview/","title":"Library Overview","text":"

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.

"},{"location":"01_overview/#architecture","title":"\ud83c\udfd7\ufe0f Architecture","text":"
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.

"},{"location":"01_overview/#how-one-resource-reaches-the-screen","title":"\ud83d\udd04 How one resource reaches the screen","text":"
  1. The spec is fetched at mount; specValidator runs over it.
  2. Every schema carrying x-resource becomes a ResourceConfig (name, schemaName, displayName, path, streaming, pagination).
  3. Each property becomes a FieldConfig \u2014 x-order, x-label, x-hidden, x-filterable, x-sortable, x-edit-as, x-ui-type.
  4. useResource(name) adds CRUD helpers (list, get, create, update, remove, stream?) for one resource.
  5. ListCellRenderer / DetailFieldRenderer / FormFieldRenderer dispatch to the concrete control for that FieldConfig.
"},{"location":"01_overview/#design-decisions","title":"\u26a0\ufe0f Design decisions","text":""},{"location":"01_overview/#read-next","title":"\u27a1\ufe0f Read Next","text":""},{"location":"02_spec_extensions/","title":"Spec Extensions","text":"

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).

"},{"location":"02_spec_extensions/#schema-level","title":"\ud83d\udce6 Schema level","text":"Extension Required Purpose 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
"},{"location":"02_spec_extensions/#path-level","title":"\ud83d\udce6 Path level","text":"Extension Purpose 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.

"},{"location":"02_spec_extensions/#security-auth","title":"\ud83d\udce6 Security / auth","text":"

Derived from components.securitySchemes.bearerAuth:

Extension Meaning 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.

"},{"location":"02_spec_extensions/#profile-x-profile","title":"\ud83d\udce6 Profile (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.

"},{"location":"02_spec_extensions/#validator-rules-summary","title":"\u2705 Validator rules (summary)","text":"

For each schema with x-resource:

  1. x-primary-key, x-display-format, x-list-columns present and valid.
  2. Every property has x-label and x-order.
  3. $ref without x-fk \u2192 info; x-fk target must exist and be displayable.
  4. The x-resource path exists with GET + POST.
  5. The item path /{resource}/{id} exists with GET + PUT + DELETE.
  6. If pagination params exist, limit must carry a schema.default.
"},{"location":"02_spec_extensions/#related","title":"Related","text":""},{"location":"03_admin_ui/","title":"Admin UI","text":"

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 Purpose AppProvider 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
"},{"location":"03_admin_ui/#three-ways-to-customise","title":"\ud83d\udce6 Three ways to customise","text":""},{"location":"03_admin_ui/#1-per-resource-behaviour-specconfigurationresourceconfig","title":"1. Per-resource behaviour \u2014 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.

"},{"location":"03_admin_ui/#auth","title":"\ud83d\udd10 Auth","text":"

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.

"},{"location":"03_admin_ui/#related","title":"Related","text":""}]}