import { pageMetadata } from "@/lib/page-metadata" export const metadata = pageMetadata("docs/openapi") # OpenAPI Integration Use json-render to generate dynamic forms and UIs from [OpenAPI/Swagger](https://swagger.io/specification/) schemas.

Concept: This page demonstrates how json-render can support OpenAPI schemas. The examples are illustrative and may require adaptation for production use.

## Why OpenAPI? OpenAPI specifications describe your API's endpoints, request bodies, and response schemas. By converting OpenAPI schemas to json-render specs, you can: - Automatically generate forms for API endpoints - Display API responses with type-aware rendering - Keep your UI in sync with your API schema - Let AI generate UIs that match your API contracts ## Example OpenAPI Schema A typical OpenAPI schema for a request body: ```json { "openapi": "3.0.0", "paths": { "/users": { "post": { "summary": "Create a new user", "operationId": "createUser", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateUserRequest" } } } } } } }, "components": { "schemas": { "CreateUserRequest": { "type": "object", "required": ["email", "name"], "properties": { "name": { "type": "string", "description": "User's full name", "minLength": 1, "maxLength": 100 }, "email": { "type": "string", "format": "email", "description": "User's email address" }, "age": { "type": "integer", "minimum": 0, "maximum": 150, "description": "User's age" }, "role": { "type": "string", "enum": ["admin", "user", "guest"], "default": "user", "description": "User's role" }, "preferences": { "type": "object", "properties": { "newsletter": { "type": "boolean", "default": false }, "theme": { "type": "string", "enum": ["light", "dark", "system"] } } } } } } } } ``` ## Define an OpenAPI-to-UI Catalog Create components that map to OpenAPI data types: ```typescript import { defineCatalog } from '@json-render/core'; import { schema } from '@json-render/react'; import { z } from 'zod'; export const openapiCatalog = defineCatalog(schema, { components: { Form: { description: 'API form container', props: z.object({ operationId: z.string(), endpoint: z.string(), method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']), title: z.string().optional(), description: z.string().optional(), }), }, StringField: { description: 'String input field', props: z.object({ name: z.string(), label: z.string(), description: z.string().optional(), required: z.boolean().optional(), format: z.enum(['text', 'email', 'uri', 'uuid', 'date', 'date-time', 'password']).optional(), minLength: z.number().optional(), maxLength: z.number().optional(), pattern: z.string().optional(), placeholder: z.string().optional(), defaultValue: z.string().optional(), }), }, NumberField: { description: 'Number input field', props: z.object({ name: z.string(), label: z.string(), description: z.string().optional(), required: z.boolean().optional(), type: z.enum(['integer', 'number']).optional(), minimum: z.number().optional(), maximum: z.number().optional(), defaultValue: z.number().optional(), }), }, BooleanField: { description: 'Boolean toggle field', props: z.object({ name: z.string(), label: z.string(), description: z.string().optional(), defaultValue: z.boolean().optional(), }), }, EnumField: { description: 'Enum selection field', props: z.object({ name: z.string(), label: z.string(), description: z.string().optional(), required: z.boolean().optional(), options: z.array(z.object({ value: z.string(), label: z.string().optional(), })), defaultValue: z.string().optional(), }), }, ObjectField: { description: 'Nested object group', props: z.object({ name: z.string(), label: z.string(), description: z.string().optional(), collapsible: z.boolean().optional(), }), }, }, actions: { submit: { description: 'Submit form to API endpoint', params: z.object({ operationId: z.string() }), }, reset: { description: 'Reset form to defaults', params: z.object({}), }, }, }); ``` ## Convert OpenAPI Schema to Spec Transform OpenAPI schemas into json-render specs by recursively walking the schema properties and mapping each type to the corresponding catalog component. The converter handles nested objects, enums, arrays, and all primitive types. ## Usage Example ```tsx 'use client'; import { OpenAPIForm } from './openapi-form'; import { operationToSpec } from './openapi-to-spec'; // Your OpenAPI schema (typically loaded from your API) const createUserSchema = { type: 'object', required: ['email', 'name'], properties: { name: { type: 'string', description: "User's full name" }, email: { type: 'string', format: 'email', description: "User's email" }, age: { type: 'integer', minimum: 0, maximum: 150 }, role: { type: 'string', enum: ['admin', 'user', 'guest'], default: 'user' }, }, }; // Convert to spec const spec = operationToSpec( 'createUser', 'POST', '/api/users', createUserSchema, 'Create User', 'Add a new user to the system', ); export function CreateUserForm() { const handleSubmit = async (data: Record) => { const response = await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (response.ok) { console.log('User created!'); } }; return ; } ``` ## Auto-generating from OpenAPI Document Load and parse an OpenAPI document to generate forms for all operations: ```typescript import SwaggerParser from '@apidevtools/swagger-parser'; import { operationToSpec } from './openapi-to-spec'; export async function loadOpenAPISpecs(specUrl: string) { const api = await SwaggerParser.dereference(specUrl); const specs: Record = {}; for (const [path, methods] of Object.entries(api.paths)) { for (const [method, operation] of Object.entries(methods)) { if (!operation.requestBody?.content?.['application/json']?.schema) continue; const schema = operation.requestBody.content['application/json'].schema; const operationId = operation.operationId || `${method}_${path.replace(/\//g, '_')}`; specs[operationId] = operationToSpec( operationId, method, path, schema, operation.summary, operation.description, ); } } return specs; } // Usage const specs = await loadOpenAPISpecs('https://api.example.com/openapi.json'); // specs.createUser, specs.updateUser, etc. ``` ## Next Learn about [streaming](/docs/streaming) for progressive UI rendering.