Skip to content

ianlancetaylor/jsonschema

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JSON Schema Support

This module provides JSON schema support. A JSON schema may be used to describe the structure and values that are permitted in a JSON object. These packages support creating JSON schemas by

  • unmarshaling them from a JSON object
  • building them piece by piece by calling functions
  • inferring the JSON schema for a Go struct

Given a JSON schema, you can validate whether a Go struct or a JSON object satisfies the schema.

The implementation of JSON schemas is fairly efficient both in memory space and in determining whether an instance is valid according to a schema.

JSON Schema Versions

This module currently supports JSON schema versions draft-07, draft2019-09, and draft2020-12.

The module is flexible and support for more versions can be added.

It is possible to define your own custom JSON schema keywords, although this is not well tested. Custom vocabularies are not currently supported.

Status

The current implementation and API should be considered experimental. While the basic approach and representation is unlikely to change, details may shift.

Examples

Decode JSON schema and use it to verify objects

// VerifySchema takes a JSON encoded JSON schema and
// a set of encoded JSON values.
// If the returned error satisfies jsonschema.IsValidationError
// Then the error indicates that validating against the JSON schema failed.
// Otherwise there was an error in decoding or using the JSON values.
func VerifySchema(schemaBytes io.Reader, valsBytes []io.Reader) error {
	var schema jsonschema.Schema
	if err := json.NewDecoder(schemaBytes).Decode(&schema); err != nil {
		return err
	}
	for _, valBytes := range valsBytes {
		var val any
		if err := json.NewDecoder(valBytes).Decode(&val); err != nil {
			return err
		}
		if err := schema.Validate(val); err != nil {
			return err
		}
	}
	return nil
}

Build JSON schema

// BuildPersonSchema builds a JSON schema
// that validates records with a name and an age.
// This uses the draft202012 JSON schema version;
// other schema versions would work as well.
func BuildPersonSchema() *jsonschema.Schema {
	builder := draft202012.NewBuilder()
	// Each JSON value must be an "object",
	// meaning a map from string to value.
	builder.AddType("object")
	// Describe properties of the JSON object keys.
	builder.AddProperties(map[string]*jsonschema.Schema{
		// A name must be a string.
		"name": draft202012.NewSubBuilder().
			AddType("string").
			Build(),
		// An age must be an integer between 0 and 150.
		"age": draft202012.NewSubBuilder().
			AddType("integer").
			AddMinimum(0).
			AddMaximum(150).
			Build(),
	})
	// The name and age properties must be present.
	builder.AddRequired([]string{"name", "age"})
	// No other properties may be present.
	builder.AddAdditionalProperties(draft202012.NewSubBuilder.BoolSchema(false))
	// Build and return the schema.
	return builder.Build()
}

For example, using this function like this:

var data = []map[string]any{
	map[string]any{
		"name": "me",
		"age": 10,
	},
	map[string]any{
		"age": 10,
	},
	map[string]any{
		"name": "me",
		"age": "me2",
	},
	map[string]any{
		"name": "me",
		"age": 10,
		"citizenship": "USA",
	},
}

func main() {
	s := BuildPersonSchema()
	for i, val := range data {
		fmt.Printf("%d: %v\n", i, s.Validate(val))
	}
}

will print

0: <nil>
1: required/name: missing required field "name"
2: properties/age: instance has type "string", want "integer"
3: additionalProperties/citizenship: false schema never matches

Infer JSON schema

// Person represent a person.
type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age,omitempty"`
}

// PersonSchema returns a JSON schema for
// objects that will unmarshal into Person.
func PersonSchema() *jsonschema.Schema {
	builder := draft202012.NewBuilder()
	builder, err := draft202012.Infer[Person](builder, nil)
	if err != nil {
		// Everything here is completely under
		// the program's control,
		// so this should never fail.
		log.Fatal(err)
	}
	// This will return the JSON schema
	//
	//    {
	//     "$schema": "https://json-schema.org/draft/2020-12/schema",
	//     "type": "object"
	//     "properties": {
	//      "age": {
	//       "type": "integer"
	//      },
	//      "name": {
	//       "type": "string"
	//      }
	//     },
	//     "additionalProperties": false,
	//     "required": [
	//      "name"
	//     ],
	//    }
	return builder.Build()
}

Details

Annotations

The jsonschema package does not provide annotations to the calling code.

Validation errors are reported with a reference to the invalid location, but those references are not currently well defined JSON pointers.

Regular expressions

The "pattern" and "patternProperties" keywords, and the "format" keyword with "regex", use regular expressions. The JSON schema specification calls for these regular expressions to use the ECMA 262 regular expression syntax. However, the jsonschema package uses the Go regexp package syntax instead.

Format checking

The jsonschema package does not check the "format" keyword by default. Checking "format" requires both

Content type checking

The jsonschema package does not check the "contentEncoding", "contendMediaType", or "contentSchema" keywords.

About

JSON schema support for Go programs

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages