/jsonschema-1

golang implementation of https://json-schema.org

Primary LanguageGoMIT LicenseMIT

jsonschema

Qri GoDoc License Codecov CI Go Report Card

golang implementation of the JSON Schema Specification, which lets you write JSON that validates some other json. Rad.

Package Features

  • Encode schemas back to JSON
  • Supply Your own Custom Validators
  • Uses Standard Go idioms
  • Fastest Go implementation of JSON Schema validators (draft 7 only, benchmarks are here - thanks @TheWildBlue!)

Getting Involved

We would love involvement from more people! If you notice any errors or would like to submit changes, please see our Contributing Guidelines.

Developing

We've set up a separate document for developer guidelines!

Basic Usage

Here's a quick example pulled from the godoc:

package main

import (
	"encoding/json"
	"fmt"

	"github.com/qri-io/jsonschema"
)

func main() {
	var schemaData = []byte(`{
      "title": "Person",
      "type": "object",
      "properties": {
          "firstName": {
              "type": "string"
          },
          "lastName": {
              "type": "string"
          },
          "age": {
              "description": "Age in years",
              "type": "integer",
              "minimum": 0
          },
          "friends": {
            "type" : "array",
            "items" : { "title" : "REFERENCE", "$ref" : "#" }
          }
      },
      "required": ["firstName", "lastName"]
    }`)

	rs := &jsonschema.RootSchema{}
	if err := json.Unmarshal(schemaData, rs); err != nil {
		panic("unmarshal schema: " + err.Error())
	}

	var valid = []byte(`{
    "firstName" : "George",
    "lastName" : "Michael"
    }`)

	if errors, _ := rs.ValidateBytes(valid); len(errors) > 0 {
		panic(errors)
	}

	var invalidPerson = []byte(`{
    "firstName" : "Prince"
    }`)
	if errors, _ := rs.ValidateBytes(invalidPerson); len(errors) > 0 {
                fmt.Println(errors[0].Error())
  }

	var invalidFriend = []byte(`{
    "firstName" : "Jay",
    "lastName" : "Z",
    "friends" : [{
      "firstName" : "Nas"
      }]
    }`)
	if errors, _ := rs.ValidateBytes(invalidFriend); len(errors) > 0 {
	        fmt.Println(errors[0].Error())
  }
}

Custom Validators

The godoc gives an example of how to supply your own validators to extend the standard keywords supported by the spec.

It involves two steps that should happen before allocating any RootSchema instances that use the validator:

  1. create a custom type that implements the Validator interface
  2. call RegisterValidator with the keyword you'd like to detect in JSON, and a ValMaker function.
package main

import (
  "encoding/json"
  "fmt"
  "github.com/qri-io/jsonschema"
)

// your custom validator
type IsFoo bool

// newIsFoo is a jsonschama.ValMaker
func newIsFoo() jsonschema.Validator {
  return new(IsFoo)
}

// Validate implements jsonschema.Validator
func (f IsFoo) Validate(data interface{}) []jsonschema.ValError {
  if str, ok := data.(string); ok {
    if str != "foo" {
      return []jsonschema.ValError{
        {Message: fmt.Sprintf("'%s' is not foo. It should be foo. plz make '%s' == foo. plz", str, str)},
      }
    }
  }
  return nil
}

func main() {
  // register a custom validator by supplying a function
  // that creates new instances of your Validator.
  jsonschema.RegisterValidator("foo", newIsFoo)

  schBytes := []byte(`{ "foo": true }`)

  // parse a schema that uses your custom keyword
  rs := new(jsonschema.RootSchema)
  if err := json.Unmarshal(schBytes, rs); err != nil {
    // Real programs handle errors.
    panic(err)
  }

  // validate some JSON
  errors := rs.ValidateBytes([]byte(`"bar"`))

  // print le error
  fmt.Println(errs[0].Error())

  // Output: 'bar' is not foo. It should be foo. plz make 'bar' == foo. plz
}