Schema Form
Render a complete generated form surface for config-driven UIs. Walk a JSON Schema object-keyword subset, merge defaults with current submitted values, apply allow-list rules, then host the generated fields inside your own form.
Container image version.
Number of pods to run.
Kubernetes Service exposure mode.
Managed by the platform catalog.
Terminate HTTPS at the service edge.
schema := map[string]any{
"$schema": "https://json-schema.org/draft/2020-12/schema", // optional; ignored by Walk
"properties": map[string]any{
"replicaCount": map[string]any{"type": "integer", "title": "Replica count"},
"imageTag": map[string]any{"type": "string", "title": "Image tag"},
"tlsEnabled": map[string]any{"type": "boolean", "title": "TLS enabled"},
"serviceType": map[string]any{"enum": []any{"ClusterIP", "LoadBalancer", "NodePort"}},
"teamOwner": map[string]any{"type": "string", "title": "Team owner"},
"internalToken": map[string]any{"type": "string", "title": "Internal token"},
},
}
defaults := map[string]any{
"replicaCount": 3,
"serviceType": "ClusterIP",
"teamOwner": "platform",
}
values := map[string]any{
// Current submitted values override defaults when the form re-renders.
"serviceType": "LoadBalancer",
}
allowList := map[string]schemaform.AllowMode{
"teamOwner": schemaform.AllowModeManaged,
"internalToken": schemaform.AllowModeDisabled,
}
fields := schemaform.Walk(schema, defaults, values, allowList)
@form.Form(form.Config{ID: "config-form", Method: "post"}) {
@schemaform.Fields(schemaform.FieldsConfig{
Fields: fields,
NamePrefix: "values",
})
}Schema Subset And Version
Schema Form is a renderer, not a JSON Schema validator. Walk accepts map[string]any decoded from JSON Schema and ignores $schema, so no draft version is required. The supported keywords are the stable object/form subset shared by Draft 7, 2019-09, and 2020-12: properties, nested properties, required, type, title, description, enum, and scalar-array items.
Input schema
JSON Schema object subset decoded into map[string]any.
Version handling
$schema is optional and ignored; supported keywords are draft-stable.
Rendered keywords
properties, required, type, title, description, enum, and scalar-array items.
// Walk consumes a JSON Schema object-keyword subset. It does not validate
// against a draft and does not require or inspect "$schema".
schema := map[string]any{
"$schema": "https://json-schema.org/draft/2020-12/schema", // optional metadata
"required": []any{"replicaCount"},
"properties": map[string]any{
"replicaCount": map[string]any{
"type": "integer",
"title": "Replica count",
"description": "Number of pods to run.",
},
"serviceType": map[string]any{
"enum": []any{"ClusterIP", "LoadBalancer", "NodePort"},
},
"zones": map[string]any{
"type": "array",
"items": map[string]any{"type": "string"},
},
},
}
fields := schemaform.Walk(schema, defaults, values, allowList)Allow-List Rules
Missing allow-list paths stay editable. Managed paths remain visible but disabled and marked as managed. Disabled paths are omitted entirely.
Editable
replicaCount is not listed, so users can change it.
Managed
teamOwner stays visible, disabled, and marked managed.
Disabled
internalToken is hidden and must be pruned before save.
allowList := map[string]schemaform.AllowMode{
// Missing paths are unmanaged and editable.
"teamOwner": schemaform.AllowModeManaged, // visible, disabled, managed badge
"internalToken": schemaform.AllowModeDisabled, // hidden entirely
}
fields := schemaform.Walk(schema, defaults, values, allowList)Fallback Form From Defaults
Use FallbackFromDefaults when a system publishes defaults but no JSON Schema. It preserves the same allow-list behavior while inferring controls from the default value shape.
defaults := map[string]any{
"resources": map[string]any{
"cpu": "500m",
"memory": "512Mi",
},
"zones": []any{"us-east-1a", "us-east-1b"},
"debug": false,
}
allowList := map[string]schemaform.AllowMode{
"resources.cpu": schemaform.AllowModeManaged,
}
fields := schemaform.FallbackFromDefaults(defaults, values, allowList)Submit And Prune
Submitted values win when you re-render after validation errors. Before serializing accepted config, prune disabled paths so hidden policy-owned values cannot be posted back.
// Names post as values.replicaCount and values.resources.cpu.
posted := map[string]any{
"replicaCount": 5,
"resources": map[string]any{"cpu": "900m", "memory": "1Gi"},
"internalToken": "should-not-be-saved",
}
// Re-render with posted values after validation errors.
fields := schemaform.Walk(schema, defaults, posted, allowList)
// Before save, remove hidden policy-owned values.
schemaform.PruneDisabled(posted, allowList)
saveConfig(posted)Go API
v0.2.7The examples above cover behavior and composition. pkg.go.dev is the canonical reference for exported types, functions, methods, and Go documentation.
github.com/araihu/goshtoso/components/schemaform