Create a Form
A Form describes resource settings and the behavior those settings mean. Packaging the definition lets publishers, clients and Hosts verify the same contents. This example builds a small package, validates input and detects a changed payload.
Run the example
Allow about five minutes. You need Go, Git and a network connection for the initial source and dependency downloads. In an existing checkout, run the last two commands from the repository root.
git clone https://github.com/tako0614/takoform.git
cd takoform
go mod download
go test -v ./formpackage -run '^ExampleVerifyFS$' -count=1The test verifies this output and finishes with PASS.
GreetingPolicy 1
changed payload rejected: trueThe example uses a fictional GreetingPolicy and local temporary data. It does not sign or publish a package, or create resources on a Host.
Define settings and meaning
The setting is a greeting prefix of at most 40 characters. Creation stores it unchanged, updates replace it and deletion removes it. There is no runtime endpoint.
const exampleDefinition = `{
"apiVersion": "resources.publisher.example",
"kind": "GreetingPolicy",
"definitionVersion": "0.1.0",
"title": "Greeting policy authoring example",
"description": "Synthetic authoring fixture. The prefix is stored exactly as supplied; updating replaces it and deleting removes the policy. No runtime endpoint is provided.",
"role": "policy",
"requiresHostApi": "forms.takoform.com/v1",
"desiredSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"properties": {"prefix": {"type": "string", "minLength": 1, "maxLength": 40}},
"required": ["prefix"]
},
"lifecycleCapabilities": ["create", "read", "update", "delete", "observe"]
}`desiredSchema validates the input shape. It does not by itself explain what an update changes or whether an operation can be retried after failure. A real Form also defines lifecycle behavior, failure handling and any required Interfaces or Bindings. See Form Definition and the portability boundary for the behavior that can be offered under the same Form identity.
Build and verify the package
This code validates the definition and input, then builds a virtual filesystem containing definition.json and package-index.json. VerifyFS uses a temporary directory for verification and removes that directory afterward.
func ExampleVerifyFS() {
raw := []byte(exampleDefinition)
definition, err := formpackage.ValidateDefinition(raw)
if err != nil {
panic(err)
}
if err := formpackage.ValidateDesiredInstance(definition.DesiredSchema, map[string]any{"prefix": "Hello"}); err != nil {
panic(err)
}
schemaDigest, err := formpackage.DigestCanonicalJSON(raw)
if err != nil {
panic(err)
}
index, err := json.Marshal(map[string]any{
"apiVersion": formpackage.VersionlessFamilyPackageAPIVersion,
"kind": "FormPackage",
"formRef": formpackage.FormRef{
APIVersion: definition.APIVersion, Kind: definition.Kind,
DefinitionVersion: definition.DefinitionVersion, SchemaDigest: schemaDigest,
},
"definitionPath": "definition.json",
"files": []map[string]any{{
"path": "definition.json", "mediaType": formpackage.DefinitionMediaType,
"size": len(raw), "digest": formpackage.DigestBytes(raw),
}},
})
if err != nil {
panic(err)
}
files := fstest.MapFS{
"definition.json": &fstest.MapFile{Data: raw},
"package-index.json": &fstest.MapFile{Data: index},
}
report, err := formpackage.VerifyFS(files, ".")
if err != nil {
panic(err)
}
fmt.Println(report.FormRef.Kind, report.FileCount)
// A stale index must not validate a changed payload.
files["definition.json"].Data = append(append([]byte{}, raw...), '\n')
_, err = formpackage.VerifyFS(files, ".")
fmt.Println("changed payload rejected:", err != nil)
// Output:
// GreetingPolicy 1
// changed payload rejected: true
}schemaDigest identifies the canonicalized definition. Each file's digest and size in the index verify the exact packaged bytes. The final part adds a newline to the definition without updating the index and confirms that verification rejects the changed payload.
To distribute files, save the same definition and index, with all declared files and references present. Form Package defines the index format and calculation rules.
Prepare for publication
- Choose a publisher-controlled namespace and define the Form's purpose and behavior.
- Document settings, updates, deletion, errors and retry rules, and write tests for them.
- Follow the compatibility rules when choosing a version; do not overwrite published contents.
- Provide publisher-owned provenance, signatures and revocation information following Trust and revocation, alongside examples and limitations.
- Check that the intended Host implements the exact FormRef and admits it for the intended caller.
Successful signature verification does not decide whether to trust the publisher. Users and operators supply that policy. Registration in a central Core catalog is not what makes a Form usable.
Continue with the common model to understand references in a Snapshot, or use a Host from Go to try the API calls.