Documentation
¶
Overview ¶
Package jsonschema is an implementation of the JSON Schema specification, a JSON-based format for describing the structure of JSON data. The package can be used to read schemas for code generation, and to validate data using the draft 2020-12 and draft-07 specifications. Validation with other drafts or custom meta-schemas is not supported.
Construct a Schema as you would any Go struct (for example, by writing a struct literal), or unmarshal a JSON schema into a Schema in the usual way (with encoding/json, for instance). It can then be used for code generation or other purposes without further processing. You can also infer a schema from a Go struct.
Resolution ¶
A Schema can refer to other schemas, both inside and outside itself. These references must be resolved before a schema can be used for validation. Call Schema.Resolve to obtain a resolved schema (called a Resolved). If the schema has external references, pass a ResolveOptions with a Loader to load them. To validate default values in a schema, set [ResolveOptions.ValidateDefaults] to true.
Validation ¶
Call Resolved.Validate to validate a JSON value. The value must be a Go value that looks like the result of unmarshaling a JSON value into an [any] or a struct. For example, the JSON value
{"name": "Al", "scores": [90, 80, 100]}
could be represented as the Go value
map[string]any{
"name": "Al",
"scores": []any{90, 80, 100},
}
or as a value of this type:
type Player struct {
Name string `json:"name"`
Scores []int `json:"scores"`
}
Inference ¶
The For function returns a Schema describing the given Go type. Each field in the struct becomes a property of the schema. The values of "json" tags are respected: the field's property name is taken from the tag, and fields omitted from the JSON are omitted from the schema as well. For example, `jsonschema.For[Player]()` returns this schema:
{
"properties": {
"name": {
"type": "string"
},
"scores": {
"type": "array",
"items": {"type": "integer"}
}
"required": ["name", "scores"],
"additionalProperties": {"not": {}}
}
}
Use the "jsonschema" struct tag to provide a description for the property:
type Player struct {
Name string `json:"name" jsonschema:"player name"`
Scores []int `json:"scores" jsonschema:"scores of player's games"`
}
Deviations from the specification ¶
Regular expressions are processed with Go's regexp package, which differs from ECMA 262, most significantly in not supporting back-references. See this table of differences for more.
The "format" keyword described in section 7 of the validation spec is recorded in the Schema, but is ignored during validation. It does not even produce annotations. Use the "pattern" keyword instead: it will work more reliably across JSON Schema implementations. See learnjsonschema.com for more recommendations about "format".
The content keywords described in section 8 of the validation spec are recorded in the schema, but ignored during validation.
Controlling behavior changes ¶
Minor and patch releases of this package may introduce behavior changes as part of bug fixes or correctness improvements. To help manage the impact of such changes, the package allows you to access previous behaviors using the `JSONSCHEMAGODEBUG` environment variable. The available settings are listed below; additional options may be introduced in future releases.
- **typeschemasnull**: When set to `"1"`, the inferred schema for slices will *not* include the `null` type alongside the array type. It will also avoid adding `null` to non-native pointer types (such as `time.Time`). This restores the behavior from versions prior to v0.3.0. The default behavior is to include `null` in these cases.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Equal ¶
Equal reports whether two Go values representing JSON values are equal according to the JSON Schema spec. The values must not contain cycles. See https://json-schema.org/draft/2020-12/json-schema-core#section-4.2.2. It behaves like reflect.DeepEqual, except that numbers are compared according to mathematical equality.
Types ¶
type ForOptions ¶
type ForOptions struct {
// If IgnoreInvalidTypes is true, fields that can't be represented as a JSON
// Schema are ignored instead of causing an error.
// This allows callers to adjust the resulting schema using custom knowledge.
// For example, an interface type where all the possible implementations are
// known can be described with "oneof".
IgnoreInvalidTypes bool
// TypeSchemas maps types to their schemas.
// If [For] encounters a type that is a key in this map, the
// corresponding value is used as the resulting schema (after cloning to
// ensure uniqueness).
// Types in this map override the default translations, as described
// in [For]'s documentation.
// PropertyOrder defined in these schemas will not be used in [For] or [ForType].
TypeSchemas map[reflect.Type]*Schema
}
type ResolveOptions ¶
type ResolveOptions struct {
// BaseURI is the URI relative to which the root schema should be resolved.
// If non-empty, must be an absolute URI (one that starts with a scheme).
// It is resolved (in the URI sense; see [url.ResolveReference]) with root's
// $id property.
// If the resulting URI is not absolute, then the schema cannot contain
// relative URI references.
BaseURI string
// Loader loads schemas that are referred to by a $ref but are not under the
// root schema (remote references).
// If nil, resolving a remote reference will return an error.
Loader Loader
// ValidateDefaults determines whether to validate values of "default" keywords
// against their schemas.
// The [JSON Schema specification] does not require this, but it is recommended
// if defaults will be used.
//
// [JSON Schema specification]: https://json-schema.org/understanding-json-schema/reference/annotations
ValidateDefaults bool
}
ResolveOptions are options for Schema.Resolve.
type Resolved ¶
type Resolved struct {
// contains filtered or unexported fields
}
A Resolved consists of a Schema along with associated information needed to validate documents against it. A Resolved has been validated against its meta-schema, and all its references (the $ref and $dynamicRef keywords) have been resolved to their referenced Schemas. Call Schema.Resolve to obtain a Resolved from a Schema.
func (*Resolved) ApplyDefaults ¶
ApplyDefaults modifies an instance by applying the schema's defaults to it. If a schema or sub-schema has a default, then a corresponding missing instance value is set to the default.
The JSON Schema specification does not describe how defaults should be interpreted. This method honors defaults only on properties, and only those that are not required. If the instance is a map and the property is missing, the property is added to the map with the default. ApplyDefaults does not support structs, because it cannot know whether a field is missing in the JSON, or was explicitly set to its zero value.
ApplyDefaults can panic if a default cannot be assigned to a field.
The argument must be a pointer to the instance. (In case we decide that top-level defaults are meaningful.)
It is recommended to first call Resolve with a ValidateDefaults option of true, then call this method, and lastly call Validate.
type Schema ¶
type Schema struct {
// core
ID string `json:"$id,omitempty"`
Schema string `json:"$schema,omitempty"`
Ref string `json:"$ref,omitempty"`
Comment string `json:"$comment,omitempty"`
Defs map[string]*Schema `json:"$defs,omitempty"`
Definitions map[string]*Schema `json:"definitions,omitempty"`
// split draft 7 Dependencies into DependencySchemas and DependencyStrings
DependencySchemas map[string]*Schema `json:"-"`
DependencyStrings map[string][]string `json:"-"`
Anchor string `json:"$anchor,omitempty"`
DynamicAnchor string `json:"$dynamicAnchor,omitempty"`
DynamicRef string `json:"$dynamicRef,omitempty"`
Vocabulary map[string]bool `json:"$vocabulary,omitempty"`
// metadata
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Default json.RawMessage `json:"default,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
ReadOnly bool `json:"readOnly,omitempty"`
WriteOnly bool `json:"writeOnly,omitempty"`
Examples []any `json:"examples,omitempty"`
// validation
// Use Type for a single type, or Types for multiple types; never both.
Type string `json:"-"`
Types []string `json:"-"`
Enum []any `json:"enum,omitempty"`
// Const is *any because a JSON null (Go nil) is a valid value.
Const *any `json:"const,omitempty"`
MultipleOf *float64 `json:"multipleOf,omitempty"`
Minimum *float64 `json:"minimum,omitempty"`
Maximum *float64 `json:"maximum,omitempty"`
ExclusiveMinimum *float64 `json:"exclusiveMinimum,omitempty"`
ExclusiveMaximum *float64 `json:"exclusiveMaximum,omitempty"`
MinLength *int `json:"minLength,omitempty"`
MaxLength *int `json:"maxLength,omitempty"`
Pattern string `json:"pattern,omitempty"`
// arrays
PrefixItems []*Schema `json:"prefixItems,omitempty"`
Items *Schema `json:"-"`
ItemsArray []*Schema `json:"-"`
MinItems *int `json:"minItems,omitempty"`
MaxItems *int `json:"maxItems,omitempty"`
AdditionalItems *Schema `json:"additionalItems,omitempty"`
UniqueItems bool `json:"uniqueItems,omitempty"`
Contains *Schema `json:"contains,omitempty"`
MinContains *int `json:"minContains,omitempty"` // *int, not int: default is 1, not 0
MaxContains *int `json:"maxContains,omitempty"`
UnevaluatedItems *Schema `json:"unevaluatedItems,omitempty"`
// objects
MinProperties *int `json:"minProperties,omitempty"`
MaxProperties *int `json:"maxProperties,omitempty"`
Required []string `json:"required,omitempty"`
DependentRequired map[string][]string `json:"dependentRequired,omitempty"`
Properties map[string]*Schema `json:"properties,omitempty"`
PatternProperties map[string]*Schema `json:"patternProperties,omitempty"`
AdditionalProperties *Schema `json:"additionalProperties,omitempty"`
PropertyNames *Schema `json:"propertyNames,omitempty"`
UnevaluatedProperties *Schema `json:"unevaluatedProperties,omitempty"`
// logic
AllOf []*Schema `json:"allOf,omitempty"`
AnyOf []*Schema `json:"anyOf,omitempty"`
OneOf []*Schema `json:"oneOf,omitempty"`
Not *Schema `json:"not,omitempty"`
// conditional
If *Schema `json:"if,omitempty"`
Then *Schema `json:"then,omitempty"`
Else *Schema `json:"else,omitempty"`
DependentSchemas map[string]*Schema `json:"dependentSchemas,omitempty"`
// other
// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.8
ContentEncoding string `json:"contentEncoding,omitempty"`
ContentMediaType string `json:"contentMediaType,omitempty"`
ContentSchema *Schema `json:"contentSchema,omitempty"`
// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.7
Format string `json:"format,omitempty"`
// Extra allows for additional keywords beyond those specified.
Extra map[string]any `json:"-"`
// PropertyOrder records the ordering of properties for JSON rendering.
//
// During [For], PropertyOrder is set to the field order,
// if the type used for inference is a struct.
//
// If PropertyOrder is set, it controls the relative ordering of properties in [Schema.MarshalJSON].
// The rendered JSON first lists any properties that appear in the PropertyOrder slice in the order
// they appear, followed by all other properties that do not appear in the PropertyOrder slice in an
// undefined but deterministic order.
PropertyOrder []string `json:"-"`
}
A Schema is a JSON schema object. It supports both draft-07 and the 2020-12 draft specifications:
- Draft-07: https://json-schema.org/draft-07/draft-handrews-json-schema-01 and https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01
- Draft 2020-12: https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01 and https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-01
A Schema value may have non-zero values for more than one field: all relevant non-zero fields are used for validation. There is one exception to provide more Go type-safety: the Type and Types fields are mutually exclusive.
Since this struct is a Go representation of a JSON value, it inherits JSON's distinction between nil and empty. Nil slices and maps are considered absent, but empty ones are present and affect validation. For example,
Schema{Enum: nil}
is equivalent to an empty schema, so it validates every instance. But
Schema{Enum: []any{}}
requires equality to some slice element, so it vacuously rejects every instance.
func For ¶
func For[T any](opts *ForOptions) (*Schema, error)
It translates Go types into compatible JSON schema types, as follows. These defaults can be overridden by [ForOptions.TypeSchemas].
- Strings have schema type "string".
- Bools have schema type "boolean".
- Signed and unsigned integer types have schema type "integer".
- Floating point types have schema type "number".
- Slices and arrays have schema type "array", and a corresponding schema for items.
- Maps with string key have schema type "object", and corresponding schema for additionalProperties.
- Structs have schema type "object", and disallow additionalProperties. Their properties are derived from exported struct fields, using the struct field JSON name. Fields that are marked "omitempty" or "omitzero" are considered optional; all other fields become required properties. For structs, the PropertyOrder will be set to the field order.
- Some types in the standard library that implement json.Marshaler translate to schemas that match the values to which they marshal. For example, time.Time translates to the schema for strings.
For will return an error if there is a cycle in the types.
By default, For returns an error if t contains (possibly recursively) any of the following Go types, as they are incompatible with the JSON schema spec. If [ForOptions.IgnoreInvalidTypes] is true, then these types are ignored instead.
- maps with key other than 'string'
- function types
- channel types
- complex numbers
- unsafe pointers
This function recognizes struct field tags named "jsonschema". A jsonschema tag on a field is used as the description for the corresponding property. For future compatibility, descriptions must not start with "WORD=", where WORD is a sequence of non-whitespace characters.
func ForType ¶
func ForType(t reflect.Type, opts *ForOptions) (*Schema, error)
ForType is like For, but takes a reflect.Type
func (*Schema) CloneSchemas ¶
CloneSchemas returns a copy of s. The copy is shallow except for sub-schemas, which are themelves copied with CloneSchemas. This allows both s and s.CloneSchemas() to appear as sub-schemas of the same parent.
func (Schema) MarshalJSON ¶
func (*Schema) Resolve ¶
func (root *Schema) Resolve(opts *ResolveOptions) (*Resolved, error)
Resolve resolves all references within the schema and performs other tasks that prepare the schema for validation. If opts is nil, the default values are used. The schema must not be changed after Resolve is called. The same schema may be resolved multiple times.