govydoc
govydoc combines a typed govy validator with Go source comments
to produce JSON-serializable documentation.
The output is a flattened list of JSONPath
properties containing type details, validation rules, field documentation,
deprecation notices, and child-path relationships.
See the govydoc package source
for the complete public API.
Install
Add the package to your project:
go get github.com/nieomylnieja/govydoc/pkg/govydoc
Quick start
Assume the module path is example.com/accounts.
Define the documented type in model/account.go:
package model
// Account identifies a user of the service.
type Account struct {
// Name is the account's display name.
Name string `json:"name"`
// Email is the account's contact address.
Email string `json:"email"`
}
From main.go, attach validation rules to the type.
Pass the validator to govydoc.Generate:
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/nobl9/govy/pkg/govy"
"github.com/nobl9/govy/pkg/rules"
"github.com/nieomylnieja/govydoc/pkg/govydoc"
"example.com/accounts/model"
)
func main() {
validator := govy.New(
govy.For(func(account model.Account) string { return account.Name }).
WithName("name").
Rules(rules.StringNotEmpty()),
govy.For(func(account model.Account) string { return account.Email }).
WithName("email").
Rules(rules.StringEmail()),
).
WithName("Account")
doc, err := govydoc.Generate(validator)
if err != nil {
fmt.Fprintf(os.Stderr, "generate documentation: %v\n", err)
os.Exit(1)
}
encoder := json.NewEncoder(os.Stdout)
encoder.SetIndent("", " ")
if err := encoder.Encode(doc); err != nil {
fmt.Fprintf(os.Stderr, "encode documentation: %v\n", err)
os.Exit(1)
}
}
Run the program from its module:
go run .
The encoded ObjectDoc contains a root property at $
and one entry for every supported tagged field reachable from the type.
Generated data
Each generated property combines information from reflection,
the Govy validation plan,
and source documentation:
Path identifies the property with JSONPath notation.
TypeInfo describes the Go type name, kind, and defining package.
Rules, Values, and Examples come from the Govy property plan.
TypeDoc contains the property's type documentation.
FieldDoc contains the comment attached to the struct field.
DeprecatedDoc contains text extracted from a Deprecated: marker.
ChildrenPaths lists paths structurally associated with the property.
ComponentPlans preserves validation plans
for internal components of opaque types.
For slices, ChildrenPaths may contain both the field path
and its wildcard element path at the same ancestor level.
Go documentation links are rendered as links to pkg.go.dev.
Property paths
govydoc maps common Go shapes to the following paths:
| Go shape |
Generated path |
| Root object |
$ |
| Struct field |
$.name |
| Nested field |
$.address.city |
| Slice element |
$.items[*] |
| Map key |
$.labels.*~ |
| Map value |
$.labels.* |
Only exported fields with an explicit JSON name are included.
Untagged fields, json:"-", and tags without a name are ignored.
Options
Options can be composed in the same Generate call:
doc, err := govydoc.Generate(
validator,
govydoc.WithFilteredPaths("$.internal"),
govydoc.GenerateGovyOptions(govy.PlanStrictMode()),
)
WithFilteredPaths removes PropertyDoc entries for exactly the listed paths.
It does not remove descendants or recompute ChildrenPaths,
which may still refer to filtered entries.
GenerateGovyOptions forwards options to the validation-plan generator.
See the available Govy plan options.
Use WithOpaqueType when a named composite type represents one logical value:
doc, err := govydoc.Generate(
validator,
govydoc.WithOpaqueType[json.RawMessage]("JSON"),
)
The option assigns the supplied kind to the type and stops traversal at that type.
The example generates one RawMessage property with kind JSON.
It does not generate a byte-element property below RawMessage.
Pointer layers do not affect type matching.
Validation plans below an opaque property remain in its ComponentPlans
(componentPlans in JSON).
Each component plan keeps its original absolute validation path,
type information, rules, conditions, values, examples, and hidden-value flag.
These paths describe internal components, not serialized child properties.
They do not add entries to ObjectDoc.Properties or ChildrenPaths.
For example, a duration encoded as one string can have component plans
at $.duration.unit and $.duration.value.
A unit enum or numeric bound applies to that component.
A required component does not make the duration field required.
The opaque property's own rules, values, and examples remain separate.
Component plans are retained only for types registered with WithOpaqueType.
WithFilteredPaths removes the complete opaque property when its path matches.
It does not filter component plans individually.
Development
Use the checked-in Devbox configuration
for the development toolchain.
Start the development shell:
devbox shell
Format the project, then run the CI verification commands:
just format
just test
just check
just test enables the race detector and collects package coverage.
just check runs vet, lint, spelling, whitespace, Markdown,
generated-code, and vulnerability checks.