Handle YAML data with jsonschema
mainyaml tags. To generate a schema for data that originates from YAML, the recommended workflow is to convert the YAML data to JSON first. You can use the invopop/yaml library to perform this conversion.repository·main·Indexed 21 days ago
https://github.com/invopop/jsonschemaA Go package that uses reflection to generate JSON Schemas (Draft 2020-12) from Go types. It is a feature-rich fork of alecthomas/jsonschema, optimized for modern Go versions (>= 1.24). It supports complex types, custom property fields via jsonschema and jsonschema_extras struct tags, and automatic description generation from Go comments. The package provides a Reflector for advanced configuration, including custom key naming, type mapping, and the ability to override schema logic via specific struct methods.
yaml tags. To generate a schema for data that originates from YAML, the recommended workflow is to convert the YAML data to JSON first. You can use the invopop/yaml library to perform this conversion.You can control how specific types are represented in the generated schema by defining one of the following four methods on a non-pointer object. These methods allow you to override auto-generation, extend existing schemas, or provide aliases.
JSONSchema() *Schema: Prevents auto-generation and allows you to provide a completely custom schema definition.JSONSchemaExtend(schema *jsonschema.Schema): Called after the schema is generated; use this to manipulate or add fields to the existing schema.JSONSchemaAlias() any: Allows you to specify an alternative type to be used when reflecting this object.JSONSchemaProperty(prop string) any: Called for every property inside a struct, allowing you to provide an alternative object for conversion into a schema.type CompactDate struct {
Year int
Month int
}
// Custom schema definition using JSONSchema()
func (CompactDate) JSONSchema() *Schema {
return &Schema{
Type: "string",
Title: "Compact Date",
Description: "Short date that only includes year and month",
Pattern: "^[0-9]{4}-[0-1][0-9]$",
}
}Use the jsonschema.Reflect function to generate a JSON Schema from any Go type via reflection. The package supports complex types like interface{}, maps, and slices, and adheres to the JSON Schema Draft 2020-12 specification.
Key Features:
minLength, maxLength, pattern, format, etc.jsonschema_extras struct tag.Anonymous option).Requirements:
import "github.com/invopop/jsonschema"
type TestUser struct {
ID int `json:"id"`
Name string `json:"name"`
}
schema := jsonschema.Reflect(&TestUser{})You can control the generated JSON Schema properties by adding jsonschema tags to your Go struct fields. Supported keys include:
title: Sets the title of the property.description: Sets the description of the property.example: Provides one or more examples (e.g., example=joe,example=lucy).default: Sets the default value.oneof_required: Defines a oneOf constraint where specific fields are required (e.g., oneof_required=field_name).oneof_type: Defines a oneOf constraint based on types (e.g., oneof_type=string;array).enum: Defines a list of allowed values (e.g., enum=red,green,blue).type TestUser struct {
Name string `json:"name" jsonschema:"title=the name,description=The name of a friend,example=joe,example=lucy,default=alex"`
Metadata interface{} `json:"metadata,omitempty" jsonschema:"oneof_type=string;array"`
FavColor string `json:"fav_color,omitempty" jsonschema:"enum=red,green,enum=blue"`
}You can control how specific types are reflected by implementing one of the following interfaces on your Go types:
customSchemaImpl)Implement JSONSchema() *Schema to provide a completely custom schema for a type. This is useful for types with custom JSON marshaling logic.
extendSchemaImpl)Implement JSONSchemaExtend(*Schema) to modify the generated schema after it has been created.
aliasSchemaImpl)Implement JSONSchemaAlias() any to tell the reflector to use a different type's schema instead of the current type's schema.
propertyAliasSchemaImpl)Implement JSONSchemaProperty(prop string) any to determine if a specific property should use a different type for its contents.
type MyType struct{}
// Using customSchemaImpl to provide a manual schema
func (m MyType) JSONSchema() *jsonschema.Schema {
return &jsonschema.Schema{
Type: "string",
Format: "custom-format",
}
}When creating a jsonschema.Reflector instance, you can enable ExpandedStruct. If set to true, the top-level struct will not reference itself in the definitions (it will be rendered inline rather than via a $ref). Note that the type passed to Reflect must be a struct type.
// Example of how ExpandedStruct affects output
type SomeBaseType struct {
SomeBaseProperty int `json:"some_base_property"`
// ...
}
// If ExpandedStruct is true, the top level struct is not a $ref to a definition.When AddGoComments is called, it builds a CommentMap using fully qualified names as keys. This allows the Reflector to look up descriptions during schema generation.
The key format used in the CommentMap is:
{package_path}.{Type_Name}{package_path}.{Type_Name}.{Field_Name}Example mapping:
github.com/acme/apiUserEmailgithub.com/acme/api.User.EmailTo add arbitrary or custom properties to the generated JSON Schema object that are not part of the standard JSON Schema specification, use the jsonschema_extras struct tag. The values provided in the tag are mapped directly to the property in the resulting schema.
Example: jsonschema_extras:"a=b,foo=bar,foo=bar1" will result in a property a with value b, and a property foo with an array ["bar", "bar1"].
type TestUser struct {
Tags map[string]interface{} `json:"tags,omitempty" jsonschema_extras:"a=b,foo=bar,foo=bar1"`
}If your JSON keys differ from your Go struct field names (e.g., using snake_case for APIs), you can provide a mapping function to the Reflector.KeyNamer option.
If a field has an explicit json:"..." tag, the KeyNamer function will receive the value of that tag as the input string instead of the Go field name.
import "github.com/stoewer/go-strcase"
r := new(jsonschema.Reflector)
r.KeyNamer = strcase.SnakeCase
s := r.Reflect(&User{})You can use the AddGoComments(base, path string) method on a jsonschema.Reflector to parse your Go source files and automatically use existing Go comments as the description field in your JSON schema.
To use this, provide the fully qualified Go module URL as the base argument and the directory path containing the source files as the path argument.
r := new(Reflector)
if err := r.AddGoComments("github.com/invopop/jsonschema", "./"); err != nil {
// handle error
}
s := r.Reflect(&User{})Use the Validate() method on an ID to ensure it is a properly formatted URI. The validation checks that:
.).http or https.err := myID.Validate()
if err != nil {
// handle invalid schema ID
}Use ReflectFromType to generate a root schema directly from a reflect.Type using default settings.
import (
"reflect"
"github.com/invopop/jsonschema"
)
schema := jsonschema.ReflectFromType(reflect.TypeOf(User{})