jsonschema

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

README

jsonschema

Validation against families of JSON Schema documents, with every failure as a JSON pointer, a keyword and a short message, in a stable order. A layer over santhosh-tekuri/jsonschema/v6 with its own format checkers and an ECMA-262 pattern engine.

Go Reference test Go

Published schema families, such as the Open Charge Alliance's OCPP and OSCP schemas, are sets of files that refer to each other by file name, $id or JSON pointer, and sometimes name a file differently from its $id. This module keeps such a set in memory as added (corrections can be applied to a decoded copy first), resolves the references, validates with santhosh-tekuri/jsonschema/v6, and reports each failure in a form a protocol reply can carry. Every format of JSON Schema 2020-12 is checked by this module's own code, and patterns are read as ECMA-262 regular expressions. A pre-pass (CheckSchemas) refuses schemas that use keywords outside a dialect; the OCA's OCPP dialect is included. No cgo. Written for SigmaM2M, a oneM2M platform, where it validates OCPP 1.6 to 2.1 and OSCP 2.0 messages and its OpenAPI requests.

Features

Feature Status
Drafts 4, 6, 7, 2019-09 and 2020-12, chosen by each document's $schema; Options.DefaultDraft for documents that name none (draft-07 if unset) yes (the library's)
Schema families: references by $id, by a document added under the whole URL, then by file name; nothing fetched from the network yes
Failures as pointer, keyword and our message, in a stable order (ValidationError, Translate, Style) yes
Numbers kept exact (Decode with json.Number; integer accepts any number whose fraction is zero) yes
format as each draft says: an assertion in drafts 4, 6 and 7, an annotation in 2019-09 and 2020-12; Options.AssertFormat asserts it everywhere; the 2020-12 format-assertion vocabulary is honoured yes
Formats date-time, date, time (ranges, offsets, leap seconds), duration, email, idn-email, hostname, idn-hostname, ipv4, ipv6, uri, uri-reference, iri, iri-reference, uri-template, json-pointer, relative-json-pointer, uuid, regex, all with our messages yes
idn-hostname by IDNA2008 (RFC 5891 to 5893): Punycode round trip, derived property, CONTEXTJ and CONTEXTO rules, Bidi rule, after a lookup mapping yes, see the notes below
pattern, patternProperties and format regex as ECMA-262 with the u flag: lookahead, lookbehind, back references, named groups, \p{...}, pattern modifiers (CompileRegexp); Options.GoRegexp keeps Go's RE2 syntax yes
contentEncoding, contentMediaType and contentSchema as assertions (Options.AssertContent); annotations by default yes
Dialects: refuse keywords outside an allowed set before use (Dialect, CheckSchemas, OCA()); 2019-09 and 2020-12 keywords, embedded $id resources, $anchor, $dynamicRef and $recursiveRef followed yes
$dynamicRef, $recursiveRef and $vocabulary across a family of documents (custom meta-schemas in the set) yes (the library's), tested here
Output formats of the specification: flag, basic, detailed, verbose, with annotations (Set.Output, OutputUnit) yes, see the notes below
A number written with a fraction or exponent (1.0) refused as integer in draft-04 yes, with Options.Draft4Integer; accepted by default
Validate a Go value (struct tags and MarshalJSON apply) yes (Set.ValidateGo)
Build schemas in code as decoded values (AddValue); no builder API

Notes on the checkers:

  • idn-hostname maps each label by the UTS 46 mapping table (nontransitional) as golang.org/x/net/idna carries it, then checks it by IDNA2008. The IDNA2008 derived property is computed from Go's Unicode tables and golang.org/x/text, not read from the IANA registry, so it follows the Unicode version of the Go release used. The joining types for the CONTEXTJ rules come from golang.org/x/net/idna.
  • Patterns that need no lookaround, back reference, multiline anchor or counted repeat above 1000 are translated to Go's RE2 syntax and match in linear time. Others run on a backtracking matcher that follows the ECMA-262 matching rules and gives up, as no match, after MaxSteps steps (about 40 ms on the laptop it was measured on), so a hostile input cannot hold a validator. Case folding under i is simple case folding. \p{Script=...} takes script names (Greek), not four-letter codes (Grek), and Script_Extensions is read as Script. Binary properties are those in Go's tables plus Any, ASCII, Assigned, Alphabetic, Lowercase, Uppercase, Math, ID_Start, ID_Continue and Default_Ignorable_Code_Point; emoji properties are refused at compile.
  • email is an RFC 5321 mailbox: dot-string or quoted local part of at most 64 octets, a host name or an IPv4 or IPv6 address literal. Comments, display names and other address literals are refused.

Notes on the output formats:

  • Failures in basic and detailed are the library's, found in context, with our messages in error. The verbose tree evaluates each subschema on the part of the instance it applies to and records valid branches too; a subschema reached through $dynamicRef or $recursiveRef is shown at its static target. When that alone cannot explain a failure (the dynamic scope changed the target), verbose shows the library's failure tree instead. The result's valid is always that of Validate.
  • Annotations come from title, description, default, examples, deprecated, readOnly, writeOnly, format, the content keywords, and the applicators (properties, patternProperties, additionalProperties, unevaluatedProperties, prefixItems, items, contains, unevaluatedItems). Unknown keywords are not collected as annotations.
  • absoluteKeywordLocation is the $id of the enclosing schema resource and a pointer in it; a document without $id is mem:/// and its name in the set.
  • The library's own OutputUnit names the property AbsoluteKeywordLocation (capital A) in JSON; this module's uses the specification's absoluteKeywordLocation.
  • Verbose evaluates each subschema again, so it costs several times a validation (see Benchmarks).

Choosing a Go JSON Schema validator

Compared from each project's source or README at the versions named, in October 2026. Check the projects themselves before relying on a row.

this module v0.3.0 santhosh-tekuri/jsonschema v6.0.3 kaptinlin/jsonschema v0.9.10 xeipuuv/gojsonschema v1.2.0
What it is a layer over santhosh-tekuri v6 a validator a validator a validator
Drafts 4, 6, 7, 2019-09, 2020-12 4, 6, 7, 2019-09, 2020-12 4, 6, 7, 2019-09, 2020-12 4, 6, 7
Default draft without $schema 7, settable 2020-12, settable 2020-12 not compared
JSON Schema Test Suite every required and optional test passes, and the output tests (below) run in its CI vendored as a git submodule not compared
Formats idn-hostname, idn-email yes no checker not compared not compared
Patterns ECMA-262 (u flag), RE2 where possible Go RE2, or an engine you plug in Go RE2 Go RE2
Families with mismatched file names and $id yes through a custom loader not compared not compared
Failures a list in a stable order with our wording; the specification's flag, basic, detailed and verbose flag, basic and detailed (no verbose, no annotations) flag and list (the newer output proposal) its own
Keyword dialect refusal before use yes vocabularies (2019-09 and later) dialects no
Go structs as their JSON (ValidateGo) no validated directly, and unmarshalled with defaults no
Schemas built in code as decoded values no a constructor API no
Last release v0.x 2026-08 2026-10 2019-10

Pick this module when you validate protocol messages against a family of published schemas and need failures you can put in a reply, in the same order every time, or when patterns and formats must follow the specification exactly. Pick santhosh-tekuri/jsonschema/v6 directly when you want your own extension vocabularies or the fastest failure path (it is the engine here; see Benchmarks). Pick kaptinlin/jsonschema to build schemas in code with a typed API or to fill struct defaults while unmarshalling.

Benchmarks

The nested module bench/ (Go 1.27, which kaptinlin v0.9.10 requires) validates one OCPP-shaped 2020-12 schema (nested objects and arrays, $ref, enums, bounds, a pattern, a format) with each validator, after TestAgree checks that they agree. On an Apple M4 Pro, Go 1.27.0, go test -bench . -benchmem gave:

this module santhosh-tekuri v6.0.3 kaptinlin v0.9.10
Compile the schema 137 µs 143 µs 41 µs
Validate a decoded valid instance 4.7 µs 4.9 µs 23 µs
Validate a decoded instance with four failures 6.5 µs (and the failure list) 3.6 µs 18 µs
Decode and validate, valid 10.8 µs 10.5 µs 28 µs
Decode and validate, four failures 10.6 µs 7.5 µs 22 µs

This module adds nothing to a valid instance; on a failure it spends about 3 µs building the ordered list. Output on the failing instance took 15 µs (basic, detailed) and 72 µs (verbose).

Install

go get github.com/cB-Sigma/jsonschema@latest

Requires Go 1.26 or later.

Quick start

import "github.com/cB-Sigma/jsonschema"

set := jsonschema.NewSet(jsonschema.Options{})
err := set.Add("meter.json", meterSchema)    // refers to "reading.json"
err = set.Add("reading.json", readingSchema)

err = set.ValidateJSON("meter.json", body)
var v jsonschema.ValidationError
if errors.As(err, &v) {
	for _, e := range v {
		fmt.Println(e.Path, e.Keyword, e.Message) // "/reading/kWh minimum ..."
	}
}

To assert format in 2019-09 and 2020-12 documents too:

set := jsonschema.NewSet(jsonschema.Options{AssertFormat: true})

Example and ExampleNewSet_options in example_test.go run these and check their output.

Documentation

API reference: https://pkg.go.dev/github.com/cB-Sigma/jsonschema

Package What it does
jsonschema (module root) NewSet and Options, Set.Add, AddValue, Compile, ValidateJSON, Validate, ValidateGo, Decode; Output, OutputFormat and OutputUnit (the specification's output formats); ValidationError, Translate and Style (the wording of the library's failures, for callers that compile with the library themselves); CompileRegexp and Regexp (ECMA-262 patterns, usable as the library's regexp engine); Dialect, CheckSchemas, OCA(), Keywords(), Keywords2020()
testsuite (nested module, tests only) runs the JSON Schema Test Suite against this module
bench (nested module, benchmarks only) compares this module with santhosh-tekuri/jsonschema/v6 and kaptinlin/jsonschema

Third-party types: no exported signature names a type of santhosh-tekuri/jsonschema/v6. Translate is the one deliberate tie: it reads that library's v6 error values, for callers that compile schemas with v6 themselves (an OpenAPI validator, for one), so this module stays on v6 for the whole of its v1.

Errors: branch with errors.As on ValidationError and on each Error.Keyword and Error.Path, never on message text. Other errors start with jsonschema: ; a ValidationError's text has no prefix, so it can be shown to the document's sender as it is. A Set is safe for concurrent use once every document is added.

Testing

go test -race ./...

Tests carry // Covers: SIG-... comments: these are requirement IDs of the SigmaM2M project's compliance report and have no meaning outside it. FuzzRegexp checks that a translated pattern matches as the backtracking matcher does; FuzzFormats runs every checker on arbitrary strings.

JSON Schema Test Suite

The JSON-Schema-Test-Suite (MIT) is vendored in the test-only nested module testsuite/, at commit 7de0e6a06031ede80028583dd45d0cd41105ae5b (2026-10-09). Its test runs every case of draft4, draft6, draft7, draft2019-09 and draft2020-12, required and optional, through NewSet, Set.Add, Set.Compile, Decode and Set.Validate, with the suite's remotes added to each set under their http://localhost:1234/ URLs. A schema without $schema is given the directory's draft before Add, which is how a caller picks a draft other than the draft-07 default.

Each file runs with the options its tests are written for: the files under optional/format/ with AssertFormat, draft7's optional/content with AssertContent, draft4's optional/zeroTerminatedFloats with Draft4Integer, and every other file, the required format.json tests included, with the defaults (ECMA-262 patterns). Every test is also run through Set.Output in the basic, detailed and verbose formats, which must agree with Validate and list at least one error for a failure.

TestOutputSuite runs the suite's output tests (output-tests/, 4 for 2019-09 and 4 for 2020-12, all passing): the basic output must match each test's schema, and all four formats must match the specification's output schema. TestCheckSchemasSuite runs CheckSchemas over all 1,408 schemas of the required tests of every draft; it must follow their references (embedded $id resources, anchors, $dynamicRef, $recursiveRef, draft-04 id) without refusing any.

Draft Required Optional Optional, format
draft4 618/618 100/100 291/291
draft6 841/841 106/106 414/414
draft7 929/929 118/118 804/804
draft2019-09 1261/1261 158/158 885/885
draft2020-12 1301/1301 162/162 885/885

v0.1.0 passed 1292/1301 required tests of draft2020-12 (format was always asserted) and failed 841 optional tests (formats not checked, laxer email and URI checkers, Go RE2 patterns, content not asserted).

Run it with cd testsuite && go test -v ./.... The test fails when a test outside testsuite/testdata/known-failures.txt fails, when a listed test passes, or when a listed test is no longer in the suite, for required and optional tests alike. Since v0.3.0 the list is empty; v0.2.0 listed one test (draft4 optional: 1.0 as an integer), now passed with Draft4Integer.

The run found and fixed, in v0.1.0, two bugs in this module: a document added under a full URL without an $id (as the suite's remotes are) was not found by that URL, and the time and date-time checks accepted hours, minutes and offsets out of range and refused leap seconds. In v0.2.0 it found that the translation of a failed contentSchema reported the decoded content's failures at the instance's pointers. In v0.3.0 it found that CheckSchemas refused every 2019-09 and 2020-12 schema using $defs and could not follow anchors, embedded $id resources or draft-04 id.

Interop tested against
  • The JSON Schema Test Suite, above.
  • The OCA OSCP 2.0 schemas and OCPP 1.6, 2.0.1 and 2.1 schemas, through SigmaM2M's tests. On 2026-10-06 SigmaM2M's earlier hand-written validator and this module gave identical failure lists, in order, for 146,000 generated OCPP messages (68,113 of them failing) across all OCA schemas.

None. This module has no simulator.

Status

v0.x: the API may change before v1. See CHANGELOG.md.

Contributing

See CONTRIBUTING.md.

Security

See SECURITY.md to report a vulnerability privately.

Licence

Apache-2.0 (see LICENSE and NOTICE). Copyright 2026 Abhinav Gautam.

Documentation

Overview

Package jsonschema validates JSON documents against families of JSON Schema documents (the Open Charge Alliance's OCPP and OSCP schemas) with github.com/santhosh-tekuri/jsonschema/v6, and reports each failure as a JSON pointer, the schema keyword and a short message of our own.

A Set holds a family of schema documents that refer to each other by relative file name ("phase-indicator.json") or JSON pointer ("#/definitions/X", "other.json#/definitions/Y"). References are resolved against the referring document's $id; when no document carries the resolved $id, the document added under that whole URL is used, then the one added under the same file name (some published sets name a file differently from its $id). Each document is validated by the draft its $schema names (draft-04 to 2020-12; draft-07 when it names none).

What this package adds to the library: the documents are kept in memory as added (corrections can be applied to a decoded copy before Add), every format of JSON Schema 2020-12 is checked by our own checkers with our messages (formats.go, uri.go, idna.go), patterns are ECMA-262 regular expressions (ecma.go), failures are listed in a stable order (see Translate), and CheckSchemas walks the schemas before use to refuse keywords outside a dialect (dialect.go).

format is an assertion in drafts 4, 6 and 7 and an annotation in drafts 2019-09 and 2020-12, as those drafts say; Options.AssertFormat asserts it in every draft.

Instances are decoded with json.Number (Decode), so integers keep their precision and "integer" accepts any number whose fraction is zero.

Example

A family of two schema documents that refer to each other by file name; every failure comes back as pointer, keyword and message, in order.

package main

import (
	"errors"
	"fmt"

	"github.com/cB-Sigma/jsonschema"
)

func main() {
	set := jsonschema.NewSet(jsonschema.Options{})
	_ = set.Add("meter.json", []byte(`{
		"$schema": "http://json-schema.org/draft-07/schema#",
		"type": "object",
		"properties": {
			"id": {"type": "string", "minLength": 1},
			"reading": {"$ref": "reading.json"}
		},
		"required": ["id", "reading"]
	}`))
	_ = set.Add("reading.json", []byte(`{
		"type": "object",
		"properties": {"kWh": {"type": "number", "minimum": 0}, "at": {"type": "string", "format": "date-time"}},
		"required": ["kWh"]
	}`))

	fmt.Println(set.ValidateJSON("meter.json", []byte(`{"id": "m1", "reading": {"kWh": 12.5}}`)))

	err := set.ValidateJSON("meter.json", []byte(`{"id": "", "reading": {"kWh": -1, "at": "yesterday"}}`))
	var v jsonschema.ValidationError
	if errors.As(err, &v) {
		for _, e := range v {
			fmt.Println(e.Path, e.Keyword)
		}
	}
}
Output:
<nil>
/id minLength
/reading/at format
/reading/kWh minimum

Index

Examples

Constants

View Source
const MaxSteps = 1 << 22

MaxSteps bounds the work of the backtracking matcher for one MatchString. A pattern that needs more steps does not match.

Variables

This section is empty.

Functions

func Decode

func Decode(data []byte) (any, error)

Decode parses JSON the way Validate expects instances (numbers as json.Number); trailing data is an error.

func Keywords

func Keywords() []string

Keywords returns, sorted, the draft-07 keywords (and $schema, $id, $comment, title, description, default, examples, definitions, readOnly, writeOnly and contentMediaType/contentEncoding, which carry no check) that CheckSchemas accepts by default. The slice is the caller's.

func Keywords2020 added in v0.3.0

func Keywords2020() []string

Keywords2020 returns, sorted, the keywords of drafts 2019-09 and 2020-12 that are not in Keywords. Without a dialect's Allowed, CheckSchemas accepts them in documents of those drafts. The slice is the caller's.

Types

type CheckContext

type CheckContext struct {
	// contains filtered or unexported fields
}

CheckContext is what a keyword's Check sees while CheckSchemas walks.

func (*CheckContext) Fail

func (c *CheckContext) Fail(format string, a ...any)

Fail reports a problem with the keyword's value.

func (*CheckContext) FailAt

func (c *CheckContext) FailAt(pointer, format string, a ...any)

FailAt reports a problem at another pointer of the document.

func (*CheckContext) Pointer

func (c *CheckContext) Pointer() string

Pointer is the JSON pointer of the keyword in its document.

type Dialect

type Dialect struct {
	// Keywords adds keywords to those CheckSchemas accepts, with a check
	// of their value.
	Keywords map[string]Keyword

	// Allowed says which keywords CheckSchemas accepts beside those in
	// Keywords; nil accepts the package's Keywords list.
	Allowed func(keyword string) bool

	// ObjectSchemasOnly makes CheckSchemas refuse boolean schemas (other
	// than additionalProperties: false/true, which is a keyword form).
	ObjectSchemasOnly bool
}

A Dialect is what CheckSchemas accepts in a family of schemas: the keywords allowed, and checks of a keyword's value. Validation itself is the library's (see jsonschema.go); a dialect only refuses, before use, schemas the validator would not check as their authors meant. Every field is optional. A Dialect must not be changed once a Set uses it; the Check functions may then run on several goroutines at once.

func OCA

func OCA() *Dialect

OCA is the dialect of the Open Charge Alliance's OCPP schemas: OCPP 1.6 (draft-04), OCPP 2.0.1 and 2.1 (draft-06). What they use is a subset of draft-07 with the same meaning, plus annotations: "id" (the draft-04 document identifier), "javaType" and "comment". Any other keyword is refused by CheckSchemas, so a later schema that relies on a keyword this package does not implement cannot be checked only halfway. The draft-04 boolean form of exclusiveMinimum/exclusiveMaximum means something else in draft-07 and is refused too.

type Error

type Error struct {
	// Path is the JSON pointer of the failing value in the instance.
	Path string
	// Keyword is the schema keyword that failed ("false" for a false
	// schema, "json" for a document that is not JSON).
	Keyword string
	// Message is our wording of the failure, without the path. It may
	// change in any release; branch on Keyword and Path instead.
	Message string
}

Error is one failed check.

func (Error) String

func (e Error) String() string

String formats the failure as "path: message", with "/" for the root.

type Keyword

type Keyword struct {
	// Check runs when CheckSchemas meets the keyword in a schema, to
	// report a value of the wrong shape.
	Check func(c *CheckContext, schema map[string]any, value any)
}

Keyword is the dialect's treatment of one keyword.

type Options added in v0.2.0

type Options struct {
	// Dialect, when set, is applied by CheckSchemas: keywords outside it
	// are refused and its keyword checks run. nil makes CheckSchemas
	// accept the keywords Keywords lists (and Keywords2020 in drafts
	// 2019-09 and later). The set keeps the pointer; the caller must not
	// change the dialect afterwards.
	Dialect *Dialect

	// AssertFormat makes "format" an assertion in every draft. Without
	// it, format is an assertion in drafts 4, 6 and 7, and an annotation
	// in drafts 2019-09 and 2020-12 unless the document's meta-schema
	// requires the format-assertion vocabulary (2020-12) or the format
	// vocabulary (2019-09). Unknown formats are never asserted.
	AssertFormat bool

	// AssertContent makes contentEncoding (base64) and contentMediaType
	// (application/json) assertions, and contentSchema with them (2019-09
	// and later). Without it they are annotations.
	AssertContent bool

	// GoRegexp reads "pattern", "patternProperties" and format "regex"
	// with Go's regexp syntax (RE2), as v0.1 did, instead of ECMA-262
	// (CompileRegexp).
	GoRegexp bool

	// DefaultDraft is the meta-schema URL of the draft that documents
	// without $schema are read by, one of the URLs of drafts 4, 6, 7,
	// 2019-09 and 2020-12 ("https://json-schema.org/draft/2020-12/schema").
	// Empty means draft-07, as in v0.1 and v0.2. Another value makes
	// Compile fail.
	DefaultDraft string

	// Draft4Integer refuses, in draft-04 documents, a number written with
	// a fraction or an exponent (1.0, 1e2) where "type" allows integer but
	// not number, as draft-04 defines integer. Without it a number whose
	// value is whole is an integer in every draft.
	Draft4Integer bool
}

Options choose how a Set made by NewSet validates. The zero value gives the defaults each field describes.

type OutputFormat added in v0.3.0

type OutputFormat int

OutputFormat is one of the four output structures of JSON Schema 2019-09 and 2020-12 (core specification, section 12.4 of 2020-12).

const (
	// OutputFlag is the result alone: {"valid": false}.
	OutputFlag OutputFormat = iota + 1
	// OutputBasic is a flat list: the failures of an invalid instance, or
	// the annotations of a valid one.
	OutputBasic
	// OutputDetailed is a tree that follows the schema, with only the
	// failing (or, when valid, annotating) branches, and a unit with a
	// single child replaced by that child.
	OutputDetailed
	// OutputVerbose is the whole tree: every subschema applied to every
	// instance location, valid or not.
	OutputVerbose
)

type OutputUnit added in v0.3.0

type OutputUnit struct {
	Valid bool
	// KeywordLocation is the JSON pointer of the keyword or subschema in
	// the schema, through any $ref, $dynamicRef or $recursiveRef followed.
	KeywordLocation string
	// AbsoluteKeywordLocation is the same place as an absolute URI: the
	// enclosing schema resource's $id (a document without one is
	// "mem:///" and its name in the set) and a pointer in it.
	AbsoluteKeywordLocation string
	// InstanceLocation is the JSON pointer of the value in the instance.
	InstanceLocation string
	// Error is our message for a failed keyword (empty on a unit whose
	// failure is its Errors).
	Error string
	// Annotation is the value a keyword annotates the instance with, as
	// JSON; nil when the unit carries none.
	Annotation json.RawMessage
	// Errors are the nested units that failed; Annotations the nested
	// units that passed.
	Errors      []OutputUnit
	Annotations []OutputUnit
	// contains filtered or unexported fields
}

OutputUnit is one unit of the specification's output.

func (OutputUnit) MarshalJSON added in v0.3.0

func (u OutputUnit) MarshalJSON() ([]byte, error)

MarshalJSON writes the unit with the specification's property names; a flag result is {"valid": ...} alone.

func (OutputUnit) String added in v0.3.0

func (u OutputUnit) String() string

String is the unit as indented JSON, for logs and tests.

type Regexp added in v0.2.0

type Regexp struct {
	// contains filtered or unexported fields
}

Regexp is an ECMA-262 regular expression, read with the u flag (code points, strict escapes), as JSON Schema's "pattern", "patternProperties" and format "regex" use them.

A pattern without lookaround, back references, multiline anchors or counted repeats above 1000 is translated to Go's regexp (RE2) syntax and matched in linear time; the ECMA-262 meaning of \s, ".", "$", \cX, empty classes and the rest is kept by the translation. Any other pattern is matched by a backtracking matcher that follows ECMA-262's matching rules, lookbehind included; a match that takes more than a fixed number of steps (see MaxSteps) is reported as no match.

func CompileRegexp added in v0.2.0

func CompileRegexp(src string) (*Regexp, error)

CompileRegexp parses an ECMA-262 regular expression (with the u flag) and refuses one the specification refuses: unknown escapes such as \a, inline flag groups such as (?i), Python's (?P<name>), ranges out of order, a quantifier with nothing to repeat, references to groups that do not exist, and unknown Unicode properties.

func (*Regexp) MatchString added in v0.2.0

func (r *Regexp) MatchString(s string) bool

MatchString reports whether the pattern matches anywhere in s.

func (*Regexp) String added in v0.2.0

func (r *Regexp) String() string

String returns the source of the pattern.

type Set

type Set struct {
	// contains filtered or unexported fields
}

Set is a family of schema documents. It is safe for concurrent use once every document is added.

func NewSet

func NewSet(o Options) *Set

NewSet returns an empty set with the options; the zero Options assert format in drafts 4, 6 and 7 only (see Options.AssertFormat) and refuse no keyword in CheckSchemas.

Example (Options)

In a 2020-12 document format is an annotation unless the set asserts it; patterns are ECMA-262.

package main

import (
	"fmt"

	"github.com/cB-Sigma/jsonschema"
)

func main() {
	schema := []byte(`{
		"$schema": "https://json-schema.org/draft/2020-12/schema",
		"type": "string",
		"format": "hostname",
		"pattern": "^(?!-)[a-z0-9.-]+$"
	}`)
	for _, assert := range []bool{false, true} {
		set := jsonschema.NewSet(jsonschema.Options{AssertFormat: assert})
		_ = set.Add("host.json", schema)
		fmt.Println(assert, set.ValidateJSON("host.json", []byte(`"gw..example"`)))
	}
}
Output:
false <nil>
true /: gw..example is not a host name

func (*Set) Add

func (s *Set) Add(name string, raw []byte) error

Add parses a schema document and adds it under name (its file name).

func (*Set) AddValue

func (s *Set) AddValue(name string, root any) error

AddValue adds a schema document that is already decoded (map[string]any, []any, string, bool, nil and json.Number values), for instance one read from YAML.

func (*Set) CheckSchemas

func (s *Set) CheckSchemas(name string, pointers ...string) ([]string, error)

CheckSchemas walks the schemas at the given JSON pointers of document name, and every schema they contain or reference, before any validation: keywords the dialect does not allow are refused, each keyword's Check runs, references must resolve, and a schema must not reach itself through $ref, allOf, anyOf, oneOf, not, if, then or else alone (validating it would never reach a value). Errors carry pointers into the documents. It returns the pointers of the schemas it visited in document name.

func (*Set) Compile

func (s *Set) Compile(name string) error

Compile compiles the named document (and what it references) once, so that a schema the validator refuses is reported before any validation; later validations reuse the result. The first call freezes the set: Add fails after it.

func (*Set) Names

func (s *Set) Names() []string

Names lists the documents in the set.

func (*Set) Output added in v0.3.0

func (s *Set) Output(name string, instance any, f OutputFormat) (OutputUnit, error)

Output validates an instance (as Validate does) and returns the result in one of the specification's output formats. The result's Valid is always the outcome of Validate. A schema that cannot be compiled is an error.

How the tree is built: each subschema is evaluated against the part of the instance it applies to, failures come from the library's evaluation, and annotations are read from the schema documents. A subschema reached through $dynamicRef or $recursiveRef is shown at its static target; whether it passed comes from the evaluation in context.

Example

The specification's basic output format: each failure with its keyword location, absolute keyword location and instance location.

package main

import (
	"fmt"

	"github.com/cB-Sigma/jsonschema"
)

func main() {
	set := jsonschema.NewSet(jsonschema.Options{})
	_ = set.Add("evse.json", []byte(`{
		"$schema": "https://json-schema.org/draft/2020-12/schema",
		"$id": "https://example.com/evse",
		"properties": {"evseId": {"type": "integer", "minimum": 0}}
	}`))
	inst, _ := jsonschema.Decode([]byte(`{"evseId": -1}`))
	out, _ := set.Output("evse.json", inst, jsonschema.OutputBasic)
	fmt.Println(out.Valid)
	for _, e := range out.Errors {
		fmt.Println(e.KeywordLocation, e.AbsoluteKeywordLocation, e.InstanceLocation, e.Error)
	}
}
Output:
false
/properties/evseId/minimum https://example.com/evse#/properties/evseId/minimum /evseId must be >= 0.00000000

func (*Set) Validate

func (s *Set) Validate(name string, instance any) error

Validate checks an instance decoded with Decode (or any value built of map[string]any, []any, string, bool, nil, json.Number and float64). A failed check is a ValidationError; a schema that cannot be compiled is another error.

func (*Set) ValidateGo added in v0.3.0

func (s *Set) ValidateGo(name string, v any) error

ValidateGo validates any Go value (a struct, a map, a slice) as the JSON that encoding/json makes of it, so struct tags and MarshalJSON methods apply. A value that cannot be encoded is a ValidationError with keyword "json".

func (*Set) ValidateJSON

func (s *Set) ValidateJSON(name string, data []byte) error

ValidateJSON decodes data and validates it against the named document.

type Style

type Style struct {
	// Bound prints the limit of minimum, maximum and the exclusive bounds
	// (default: eight decimals); Multiple prints multipleOf's divisor
	// (default: a fraction such as 1/100).
	Bound, Multiple func(*big.Rat) string
	// Pattern starts the message of a failed pattern (default "does not
	// match "); the pattern follows.
	Pattern string
	// ClosestBranch adds, after an anyOf or oneOf that no branch passes,
	// the failures of the branch with the fewest, each message starting
	// "(closest branch) ".
	ClosestBranch bool
	// Max caps the failures listed (0: no cap).
	Max int
	// Last lists keywords whose failures at a location come after every
	// other failure there and below it, in this order.
	Last []string
}

Style is how Translate words its messages. The zero value is the wording of a Set.

type ValidationError

type ValidationError []Error

ValidationError lists every failed check of one validation. Callers reach it with errors.As (a value, not a pointer).

func Translate

func Translate(err error, instance any, style Style, schemaAt func(loc string) map[string]any) ValidationError

Translate turns a validation failure of github.com/santhosh-tekuri/jsonschema/v6 into a ValidationError: one Error per failed check, with our messages, listed depth first by instance location (members by name, items by index), and at one location in keyword order: type, enum, const, the object, array, string and number keywords, then dependencies, contains, anyOf, oneOf and not. Failures under allOf, $ref, if/then/else and propertyNames are listed where they occur; anyOf and oneOf report one failure each (with the closest branch if the style asks). schemaAt, when not nil, finds a schema object by the location the library reports, to name multiple types in the schema's order. Any other error is returned as nil.

Translate reads the error values of major version 6 of that library: it is for callers that compile schemas with v6 themselves, and stays tied to v6 for the whole of this module's v1.

func (ValidationError) Error

func (v ValidationError) Error() string

Error joins the failures with "; ". Unlike the package's other errors it carries no "jsonschema:" prefix, so that it can be shown to the sender of the document as it is.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL