Generating from a schema
Both generators take a schema you already have and return a form definition that has already been
validated against the bundled GolemUI schemas. Anything the form cannot express exactly is listed in
diagnostics, so no field is dropped without a report.
Both tools run fromJsonSchema with the gui preset. That page describes
how each schema node maps to a widget. The same conversion is available in your own code and as a
CLI command, without the MCP server.
From a JSON Schema
Section titled “From a JSON Schema”json_generate_from_schema maps a data-shape schema (an API request body, a Zod-derived schema, …)
into widgets. Strings with a format become specialized widgets, numbers become number inputs,
booleans become checkboxes, enums become selects, and required carries through to validators. The
tool also resolves local $refs, merges allOf, turns a discriminated oneOf or anyOf into a
selector with conditional fields, and compiles if/then/else and dependentRequired into
conditions and form states.
Call:
{ "jsonSchema": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "age": { "type": "integer", "minimum": 18 }, "newsletter": { "type": "boolean" } }, "required": ["email"] }}Result:
{ "formDefinition": { "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "kind": "input", "type": "textinput", "path": "email", "label": "Email", "validator": { "type": "string", "required": true, "format": "email" } }, { "kind": "input", "type": "number", "path": "age", "label": "Age", "validator": { "type": "integer", "minimum": 18 } }, { "kind": "input", "type": "checkbox", "path": "newsletter", "label": "Newsletter" }, { "kind": "action", "type": "button", "actionType": "submit", "label": "Submit", "props": { "variant": "filled" } } ] }, "unmapped": [], "diagnostics": [], "validation": { "valid": true, "errors": [], "warnings": [], "expressionWarnings": [], "interpolationWarnings": [] }}Append submitAction: false to omit the submit button, or set layout to horizontal or grid to
change the top-level layout.
From an OpenAPI operation
Section titled “From an OpenAPI operation”json_generate_from_openapi resolves a single operation and converts its JSON request body. The
$refs in the body resolve against the whole document. Pass the spec as a parsed document or a
documentUrl, and name the operation as "METHOD /path" or an operationId.
Call:
{ "operation": "POST /users", "document": { "...": "a parsed OpenAPI 3.x document" }}Result (for an operation whose body has name: string and role: enum):
{ "resolvedOperation": { "method": "POST", "path": "/users" }, "formDefinition": { "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "kind": "input", "type": "textinput", "path": "name", "label": "Name", "validator": { "type": "string", "required": true } }, { "kind": "input", "type": "select", "path": "role", "label": "Role", "validator": { "type": "string", "enum": ["admin", "member"] }, "props": { "options": [ { "label": "Admin", "value": "admin" }, { "label": "Member", "value": "member" } ] } }, { "kind": "action", "type": "button", "actionType": "submit", "label": "Create user", "props": { "variant": "filled" } } ] }, "unmapped": [], "diagnostics": [], "validation": { "valid": true, "errors": [], "warnings": [], "expressionWarnings": [], "interpolationWarnings": [] }}The submit button’s label defaults to the operation summary (here, “Create user”) or a verb derived from the HTTP method. When the operation has no JSON request body, or a body that is not an object, the generator falls back to its parameters.
Choosing other widgets
Section titled “Choosing other widgets”Both tools accept rules and overrides. They have the same format as in
fromJsonSchema: an override changes one path, and a
rule changes every node its match selects. This call puts a mail icon on every e-mail field and
renders plan as a radio group:
{ "jsonSchema": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "plan": { "type": "string", "enum": ["free", "team", "enterprise"] }, "contact": { "anyOf": [ { "type": "object", "properties": { "phone": { "type": "string" } } }, { "type": "object", "properties": { "email": { "type": "string" } } } ] } } }, "rules": [ { "match": { "$type": "string", "format": "email" }, "props": { "icon": "mail" } } ], "overrides": { "plan": { "widget": "radiogroup" } }}The anyOf has no property that tells its branches apart, so the form renders every branch property,
optional and always visible. The result reports it in diagnostics and repeats it in unmapped:
{ "unmapped": [ { "path": "contact", "reason": "No property tells the `anyOf` branches apart (a `const` in every branch, or `discriminator.propertyName`). Every branch property is rendered, optional and always visible." } ], "diagnostics": [ { "severity": "warning", "code": "no-discriminator", "message": "No property tells the `anyOf` branches apart (a `const` in every branch, or `discriminator.propertyName`). Every branch property is rendered, optional and always visible.", "path": "contact", "pointer": "/properties/contact" } ]}After generating
Section titled “After generating”The output is already validated, but as soon as you edit a generated form — renaming a field,
adding a state, tweaking a validator — run json_validate_form_definition again
before handing it to the user.