Giter VIP home page Giter VIP logo

jsonschema's Introduction

jsonschema v5.3.1

License GoDoc Go Report Card Build Status codecov

Package jsonschema provides json-schema compilation and validation.

Benchmarks

Features:

  • implements draft 2020-12, draft 2019-09, draft-7, draft-6, draft-4
  • fully compliant with JSON-Schema-Test-Suite, (excluding some optional)
    • list of optional tests that are excluded can be found in schema_test.go(variable skipTests)
  • validates schemas against meta-schema
  • full support of remote references
  • support of recursive references between schemas
  • detects infinite loop in schemas
  • thread safe validation
  • rich, intuitive hierarchial error messages with json-pointers to exact location
  • supports output formats flag, basic and detailed
  • supports enabling format and content Assertions in draft2019-09 or above
    • change Compiler.AssertFormat, Compiler.AssertContent to true
  • compiled schema can be introspected. easier to develop tools like generating go structs given schema
  • supports user-defined keywords via extensions
  • implements following formats (supports user-defined)
    • date-time, date, time, duration, period (supports leap-second)
    • uuid, hostname, email
    • ip-address, ipv4, ipv6
    • uri, uriref, uri-template(limited validation)
    • json-pointer, relative-json-pointer
    • regex, format
  • implements following contentEncoding (supports user-defined)
    • base64
  • implements following contentMediaType (supports user-defined)
    • application/json
  • can load from files/http/https/string/[]byte/io.Reader (supports user-defined)

see examples in godoc

The schema is compiled against the version specified in $schema property. If "$schema" property is missing, it uses latest draft which currently implemented by this library.

You can force to use specific version, when $schema is missing, as follows:

compiler := jsonschema.NewCompiler()
compiler.Draft = jsonschema.Draft4

This package supports loading json-schema from filePath and fileURL.

To load json-schema from HTTPURL, add following import:

import _ "github.com/santhosh-tekuri/jsonschema/v5/httploader"

Rich Errors

The ValidationError returned by Validate method contains detailed context to understand why and where the error is.

schema.json:

{
      "$ref": "t.json#/definitions/employee"
}

t.json:

{
    "definitions": {
        "employee": {
            "type": "string"
        }
    }
}

doc.json:

1

assuming err is the ValidationError returned when doc.json validated with schema.json,

fmt.Printf("%#v\n", err) // using %#v prints errors hierarchy

Prints:

[I#] [S#] doesn't validate with file:///Users/santhosh/jsonschema/schema.json#
  [I#] [S#/$ref] doesn't validate with 'file:///Users/santhosh/jsonschema/t.json#/definitions/employee'
    [I#] [S#/definitions/employee/type] expected string, but got number

Here I stands for instance document and S stands for schema document.
The json-fragments that caused error in instance and schema documents are represented using json-pointer notation.
Nested causes are printed with indent.

To output err in flag output format:

b, _ := json.MarshalIndent(err.FlagOutput(), "", "  ")
fmt.Println(string(b))

Prints:

{
  "valid": false
}

To output err in basic output format:

b, _ := json.MarshalIndent(err.BasicOutput(), "", "  ")
fmt.Println(string(b))

Prints:

{
  "valid": false,
  "errors": [
    {
      "keywordLocation": "",
      "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/schema.json#",
      "instanceLocation": "",
      "error": "doesn't validate with file:///Users/santhosh/jsonschema/schema.json#"
    },
    {
      "keywordLocation": "/$ref",
      "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/schema.json#/$ref",
      "instanceLocation": "",
      "error": "doesn't validate with 'file:///Users/santhosh/jsonschema/t.json#/definitions/employee'"
    },
    {
      "keywordLocation": "/$ref/type",
      "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/t.json#/definitions/employee/type",
      "instanceLocation": "",
      "error": "expected string, but got number"
    }
  ]
}

To output err in detailed output format:

b, _ := json.MarshalIndent(err.DetailedOutput(), "", "  ")
fmt.Println(string(b))

Prints:

{
  "valid": false,
  "keywordLocation": "",
  "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/schema.json#",
  "instanceLocation": "",
  "errors": [
    {
      "valid": false,
      "keywordLocation": "/$ref",
      "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/schema.json#/$ref",
      "instanceLocation": "",
      "errors": [
        {
          "valid": false,
          "keywordLocation": "/$ref/type",
          "absoluteKeywordLocation": "file:///Users/santhosh/jsonschema/t.json#/definitions/employee/type",
          "instanceLocation": "",
          "error": "expected string, but got number"
        }
      ]
    }
  ]
}

CLI

to install go install github.com/santhosh-tekuri/jsonschema/cmd/jv@latest

jv [-draft INT] [-output FORMAT] [-assertformat] [-assertcontent] <json-schema> [<json-or-yaml-doc>]...
  -assertcontent
    	enable content assertions with draft >= 2019
  -assertformat
    	enable format assertions with draft >= 2019
  -draft int
    	draft used when '$schema' attribute is missing. valid values 4, 5, 7, 2019, 2020 (default 2020)
  -output string
    	output format. valid values flag, basic, detailed

if no <json-or-yaml-doc> arguments are passed, it simply validates the <json-schema>.
if $schema attribute is missing in schema, it uses latest version. this can be overridden by passing -draft flag

exit-code is 1, if there are any validation errors

jv can also validate yaml files. It also accepts schema from yaml files.

Validating YAML Documents

since yaml supports non-string keys, such yaml documents are rendered as invalid json documents.

most yaml parser use map[interface{}]interface{} for object,
whereas json parser uses map[string]interface{}.

so we need to manually convert them to map[string]interface{}.
below code shows such conversion by toStringKeys function.

https://play.golang.org/p/Hhax3MrtD8r

NOTE: if you are using gopkg.in/yaml.v3, then you do not need such conversion. since this library returns map[string]interface{} if all keys are strings.

jsonschema's People

Contributors

adamcohen2 avatar aeneasr avatar bvisness avatar davidjb avatar graphaelli avatar jfancher avatar kodersky avatar mathieuk avatar oetiker avatar rhomel avatar santhosh-tekuri avatar scop avatar superstas avatar yvesf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsonschema's Issues

Unknown format is a valid value for JSON schema

JSON schema does not restrict format values, it is unfortunate that validator fails to load a schema with unknown format:

panic: jsonschema: Compile("schema.json"): json-schema "schema.json" compilation failed. Reason:

I[#] S[#] doesn't validate with "http://json-schema.org/draft-07/schema#"

  I[#/format] S[#/properties/format/format] "uuid" is not valid "format"

goroutine 9 [running]:

	/...../vendor/github.com/santhosh-tekuri/jsonschema/compiler.go:105 +0x13e

I think unknown format should be ignored as if there was no format value at all, but I could not find nice words in spec to support my opinion.

Add validation error context for downstream propagation

At the moment, the context returned by validation errors is very small. For example, a "required" error does not include the pointer to the required field itself, but to it's parent. However, sometimes it's required to know the exact path to present a suitable human readable error.

Another issue is that it should be possible to internationalize the error messages in cases where we want to support multiple languages. It would also be nice if it was possible to provide a custom error format.

This can be solved by either including all of the context necessary to render a proper error message, or by allowing the registration of error string format. I'd definitely think the former being the easier (and less polluting) approach.

Validation mystery

Hi, I have a schema which looks like this attached file actual-schema.json

I am validating this file agains the data filecli.jsonfiles.

actual-schema.json.txt
cli.json.txt

Validation code looks like this:

func TestValidate(t *testing.T) {
	sch, err := jsonschema.Compile("testdata/actual-schema.json")
	if err != nil {
		log.Fatalf("%#v", err)
	}

	data, err := ioutil.ReadFile("testdata/cli.json")
	if err != nil {
		log.Fatal(err)
	}

	var v interface{}
	if err := json.Unmarshal(data, &v); err != nil {
		log.Fatal(err)
	}

	if err = sch.Validate(v); err != nil {
		log.Fatalf("%#v", err)
	}
}

If my cli.json file looks like this:

{
    "test": {
        "abc": {
            "ABC-noABC": "abc-data",
            "def": {
                "DEF": "def-data"
            }
        }
    }
}

where required tag ABC is missing, I get a right error message from the program like this:
time="2022-06-27T22:12:15-04:00" level=fatal msg="[I#] [S#] doesn't validate with actual-schema.json#\n [I#/test] [S#/properties/test/anyOf] anyOf failed\n [I#/test/abc] [S#/properties/test/anyOf/0/properties/abc/required] missing properties: 'ABC'"

This text passes the validation.
{
    "test": {
        "abc": {
            "ABC": "abc-data",
            "def": {
                "DEF-missing": "def-data"
            }
        }
    }
}

But, if I make the "DEF" miss which is also a required argument, the program does not prompt with an error.

Can someone clarify why it passes?

Thank you.

go install installs old version

Wanted to install jv 5.0, but go install couldn't figure it out:

$ go version
go version go1.17.1 darwin/amd64
$ go install github.com/santhosh-tekuri/jsonschema/cmd/jv@v5 
go install: github.com/santhosh-tekuri/jsonschema/cmd/jv@v5: no matching versions for query "v5"

Using @latest works, but installs v1:

$ go install github.com/santhosh-tekuri/jsonschema/cmd/jv@latest
go: downloading github.com/santhosh-tekuri/jsonschema v1.2.4

Not sure if this is a go issue or if the repo needs a cmd/jv/go.mod file to fix it.

Feature: support for meta-schemas

I'm trying to create a meta-schema and later on validate the schema with that meta-schema. However, when :

"$schema": "some_non_draft_ url"

It breaks. I checked that the URL only must match with a draft URL. If so, how do I implement a meta-schema?

consider exposing a resolver that can handle any URL

The current loading / resource mechanism requires one to know all of the urls by default... consider providing a way to provide a resource that can just answer any url or return not found and then allow people to just implement multiple resolvers with a priority order. Such as "local FS", then "web"

Inclusion of InstanceLocation for required and additionalProperties errors

I've just come across this and it's working great :) However, one thing I've noticed that's a bit awkward is - any errors caused by a violation of a required or additionalProperties rule doesn't tell you where in the JSON the violation occurred.

For everything else I get an InstanceLocation that is the JSON Pointer to the property that was invalid. For these two I just get "", so I can't have my service indicate which property was either missing but required, or was unexpectedly present.

I do get this come through in the Message so the validator obviously knows which property it is, but it just doesn't actually return it to the client.

Cheers

Only the first error is returned

When validating a JSON document that contains multiple errors, only the trace for the first error is returned. For example:

{
  "items" : {
     "type" : "integer" 
  }
}

with a document [ "foo", "bar" ] should produce two errors, but only one error for "foo" is returned.
Similarly if we expand the schema to:

{
  "items" : {
     "type" : "integer" 
  },
  "if" : true,
  "then" : false
}

Only the error for the if/else is returned. All other implementations I tested return all errors and don't short-circuit. Example using AJV
Judging from the code it seems pretty intentional, so I'm not actually sure you see it as a bug, but it might be worth mentioning in the README or making this behaviour configurable as it is not the default behaviour I expected (although saying that I'm probably biased).

Usage instructions perhaps?

The docs are pretty sparse on how to actually use it for validation.
So I create a compiler then what? How do I feed it the other json schemas? How do I validate actual jsons? Can I assert a type of parsed JSON with this? Can I extend Compiler struct to have my own $id/$ref parsing logic?

Feature: Strict Validation

I'm switching from Ajv, which has a number of strict options that I will miss. Any chance support for some of these could be added? Will help prevent me from making typos like descripxtion.

Feature: formating of errormessages for display to end user

I'm trying to figure out how jsonschema.ValidationError are to be translated to something understandable to an end user, or for that matter looped to for example mark input fields for the error.

I get string like "additioalProperties 'test1', 'test2', 'test3' is not allowed" or "missing properties: 'firstName'". and no separate field to check the list of the fields with the error or what a machine understandable version of the error is.

Am I missing something or isn't there a way to do anything except showing the result as a string blob?

Validating using part of document?

Hi, I'm looking at various golang JSON-Schema validators, I like this one mostly because it exposes the Schema struct. But my use case is to decode documents that contains JSON schema (and JSON pointers) but is not a pure JSON Schema document. And then validating structs against Schema in that document.

This does not seem possible right now (results in 'unknown $schema "some url"'). Do you have any advice to get around this?

Thanks.

Invalid pointer found on stack

When calling jsonschema.Compile() with a particular schema, I get a stack trace. I've been able to successfully call jsonschema.Compile() with other schemas.

Go Version: 1.10.1 darwin/amd64

Schema:
I used https://www.jsonschemavalidator.net/ to validate that this schema does not have errors.

{
    "schema": "http://json-schema.org/schema#",
    "title": "Tag Action",
    "type": "object",
    "properties": {
        "tags": {
            "description": "The tags to be added to the alert.",
            "type": "array",
            "items": {
                "description": "A single tag to be added to the alert.",
                "type": "string"
            }
        }
    },
    "required": ["tags"]
}

My Code:

func LoadAndValidateJSONConfig(schemaFileName string, configFileName string, destinationStruct interface{}) error {
	schema, err := jsonschema.Compile(schemaFileName)
	if err != nil {
		return errors.Wrap(err, fmt.Sprintf("Error compiling JSON schema \"%s\"", schemaFileName))
	}

	f, err := os.Open(configFileName)
	if err != nil {
		return errors.Wrap(err, fmt.Sprintf("Error opening config file \"%s\" for verification", configFileName))
	}
	defer f.Close()

	if err = schema.Validate(f); err != nil {
		return errors.Wrap(err, "Error while validating config against the provided schema")
	}

	return LoadJSONConfig(configFileName, destinationStruct)
}

Trace:

runtime: bad pointer in frame github.com/santhosh-tekuri/jsonschema.(*Schema).validate at 0xc4201d4b78: 0x4
fatal error: invalid pointer found on stack

runtime stack:
runtime.throw(0x635b987, 0x1e)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/panic.go:616 +0x81 fp=0x7ffeefbfebe0 sp=0x7ffeefbfebc0 pc=0x602aea1
runtime.adjustpointers(0xc4201d4230, 0x7ffeefbfecd8, 0x7ffeefbff098, 0x64cf008, 0x64e0560)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/stack.go:592 +0x23e fp=0x7ffeefbfec50 sp=0x7ffeefbfebe0 pc=0x604175e
runtime.adjustframe(0x7ffeefbfefa8, 0x7ffeefbff098, 0x64e0560)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/stack.go:663 +0x325 fp=0x7ffeefbfed08 sp=0x7ffeefbfec50 pc=0x6041aa5
runtime.gentraceback(0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0xc420000180, 0x0, 0x0, 0x7fffffff, 0x636b508, 0x7ffeefbff098, 0x0, ...)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/traceback.go:310 +0x12d3 fp=0x7ffeefbff010 sp=0x7ffeefbfed08 pc=0x604b2b3
runtime.copystack(0xc420000180, 0x10000, 0x7ffeefbff201)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/stack.go:891 +0x26e fp=0x7ffeefbff1c8 sp=0x7ffeefbff010 pc=0x604258e
runtime.newstack()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/stack.go:1063 +0x310 fp=0x7ffeefbff358 sp=0x7ffeefbff1c8 pc=0x60429a0
runtime.morestack()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:480 +0x89 fp=0x7ffeefbff360 sp=0x7ffeefbff358 pc=0x6052989

goroutine 1 [copystack]:
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420160000, 0x42d6100, 0xc42015ab70, 0x0, 0x0)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:144 +0x4b70 fp=0xc4201d2748 sp=0xc4201d2740 pc=0x629a380
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420153b80, 0x42d6100, 0xc42015ab70, 0x1a, 0x0)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:153 +0x4895 fp=0xc4201d33b8 sp=0xc4201d2748 pc=0x629a0a5
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420153900, 0x42d6100, 0xc42015ab70, 0x4, 0xc4201c4758)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:225 +0x3c1 fp=0xc4201d4028 sp=0xc4201d33b8 pc=0x6295bd1
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420152280, 0x42f1a60, 0xc42013df80, 0x0, 0x0)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:304 +0x30e4 fp=0xc4201d4c98 sp=0xc4201d4028 pc=0x62988f4
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420152a00, 0x42f1a60, 0xc42013df80, 0x0, 0x0)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:153 +0x4895 fp=0xc4201d5908 sp=0xc4201d4c98 pc=0x629a0a5
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420152780, 0x42f1a60, 0xc42013df80, 0x5, 0xc4201c4648)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:225 +0x3c1 fp=0xc4201d6578 sp=0xc4201d5908 pc=0x6295bd1
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420152280, 0x42f1a60, 0xc42013df50, 0x0, 0x0)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:304 +0x30e4 fp=0xc4201d71e8 sp=0xc4201d6578 pc=0x62988f4
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420165b80, 0x42f1a60, 0xc42013df50, 0x4, 0xc4201c4868)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:153 +0x4895 fp=0xc4201d7e58 sp=0xc4201d71e8 pc=0x629a0a5
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420165900, 0x42f1a60, 0xc42013df20, 0xa, 0xc4201c4538)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:349 +0x2bb7 fp=0xc4201d8ac8 sp=0xc4201d7e58 pc=0x62983c7
github.com/santhosh-tekuri/jsonschema.(*Schema).validate(0xc420152280, 0x42f1a60, 0xc42013def0, 0x5ff, 0xc4201c4480)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:304 +0x30e4 fp=0xc4201d9738 sp=0xc4201d8ac8 pc=0x62988f4
github.com/santhosh-tekuri/jsonschema.(*Draft).validateSchema(0x44fb980, 0x635bc77, 0x1f, 0x0, 0x0, 0x42f1a60, 0xc42013def0, 0x4312d80, 0xc42013df01)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/compiler.go:43 +0x82 fp=0xc4201d97e8 sp=0xc4201d9738 pc=0x628c972
github.com/santhosh-tekuri/jsonschema.Compiler.compileRef(0x0, 0xc42013dec0, 0x635bc00, 0x44fb980, 0xc4201c8000, 0x0, 0x635bc77, 0x1f, 0x6353711, 0x1, ...)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/compiler.go:161 +0xd45 fp=0xc4201d99f8 sp=0xc4201d97e8 pc=0x628e3d5
github.com/santhosh-tekuri/jsonschema.(*Compiler).Compile(0xc420177ad0, 0x635bc77, 0x1f, 0x0, 0x0, 0x0)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/compiler.go:148 +0x164 fp=0xc4201d9aa0 sp=0xc4201d99f8 pc=0x628d4f4
github.com/santhosh-tekuri/jsonschema.Compile(0x635bc77, 0x1f, 0x20, 0x18, 0x6309b80)
/Users/msalvatore/git/GO/src/github.com/santhosh-tekuri/jsonschema/schema.go:95 +0x5b fp=0xc4201d9af8 sp=0xc4201d9aa0 pc=0x629536b
alert-middleware/common.LoadAndValidateJSONConfig(0x635bc77, 0x1f, 0xc42001b400, 0x1c, 0x6300200, 0xc4200fcde0, 0x0, 0x0)
/Users/msalvatore/git/GO/src/alert-middleware/common/util.go:27 +0x58 fp=0xc4201d9ba0 sp=0xc4201d9af8 pc=0x629c258
plugin/unnamed-959b4d77ea0d07e48cd2d1af7f5ffe965e53a6c8.(*Tag).LoadConfig(0xc4200fcde0, 0xc42001b400, 0x1c, 0xc4200fcde0, 0xc4201c43e8)
/Users/msalvatore/git/GO/src/alert-middleware/actions/tag.go:19 +0x64 fp=0xc4201d9bf0 sp=0xc4201d9ba0 pc=0x629c844
alert-middleware/common.(*PluginLoader).LoadActionPlugin(0xc420177dd0, 0xc420019920, 0x3, 0xc42001b400, 0x1c, 0x13, 0x0, 0x0, 0x428e9ae)
/Users/msalvatore/git/GO/src/alert-middleware/common/plugin_loader.go:38 +0x284 fp=0xc4201d9d40 sp=0xc4201d9bf0 pc=0x42960d4
main.main()
/Users/msalvatore/git/GO/src/alert-middleware/main.go:48 +0x3c3 fp=0xc4201d9f88 sp=0xc4201d9d40 pc=0x4296fd3
runtime.main()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:198 +0x212 fp=0xc4201d9fe0 sp=0xc4201d9f88 pc=0x402e4e2
runtime.goexit()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc4201d9fe8 sp=0xc4201d9fe0 pc=0x40577d1

goroutine 2 [force gc (idle)]:
runtime.gopark(0x4361eb0, 0x4504d10, 0x434c79b, 0xf, 0x4361d14, 0x1)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:291 +0x11a fp=0xc420044768 sp=0xc420044748 pc=0x402e93a
runtime.goparkunlock(0x4504d10, 0x434c79b, 0xf, 0x14, 0x1)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:297 +0x5e fp=0xc4200447a8 sp=0xc420044768 pc=0x402e9ee
runtime.forcegchelper()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:248 +0xcc fp=0xc4200447e0 sp=0xc4200447a8 pc=0x402e77c
runtime.goexit()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc4200447e8 sp=0xc4200447e0 pc=0x40577d1
created by runtime.init.4
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:237 +0x35

goroutine 3 [GC sweep wait]:
runtime.gopark(0x4361eb0, 0x4504e00, 0x434be40, 0xd, 0x4020a14, 0x1)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:291 +0x11a fp=0xc420044f60 sp=0xc420044f40 pc=0x402e93a
runtime.goparkunlock(0x4504e00, 0x434be40, 0xd, 0x14, 0x1)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:297 +0x5e fp=0xc420044fa0 sp=0xc420044f60 pc=0x402e9ee
runtime.bgsweep(0xc420070000)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/mgcsweep.go:52 +0xa3 fp=0xc420044fd8 sp=0xc420044fa0 pc=0x4020a53
runtime.goexit()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc420044fe0 sp=0xc420044fd8 pc=0x40577d1
created by runtime.gcenable
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/mgc.go:216 +0x58

goroutine 4 [finalizer wait]:
runtime.gopark(0x4361eb0, 0x45229a0, 0x434c3db, 0xe, 0x14, 0x1)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:291 +0x11a fp=0xc420045718 sp=0xc4200456f8 pc=0x402e93a
runtime.goparkunlock(0x45229a0, 0x434c3db, 0xe, 0x14, 0x1)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:297 +0x5e fp=0xc420045758 sp=0xc420045718 pc=0x402e9ee
runtime.runfinq()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/mfinal.go:175 +0xad fp=0xc4200457e0 sp=0xc420045758 pc=0x4017afd
runtime.goexit()
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc4200457e8 sp=0xc4200457e0 pc=0x40577d1
created by runtime.createfing
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/mfinal.go:156 +0x62

Add resource source map to `Schema` to support custom keywords

First of all, this library is amazing because it allows one to actually traverse a JSON Schema outside of the library (and nice solve with recursion through pointers). I wish I had found it 3 months ago!

I would like to expose the "raw" data for each schema to the outside. It would be fairly simple by basically adding a new field Raw map[string]interface{} (or alternatively a function that exposes the internal raw as to avoid potential future BC breaks in case where "raw" would be added to the schema). The field would be populated in compileMap.

Custom keywords are supported, for example, in ajv: https://github.com/epoberezkin/ajv/blob/master/CUSTOM.md

I also believe that I've read somewhere that Draft8 will have room for custom keywords (not 100% sure)?

While this approach is well short of actually "embedding" the custom keyword in this library, it would at least allow the consumer of that library to have access to that data.

Map multiple components/schemas to a single openapiv3 document

Hi Santhosh,

Any chance you could help out Pierre regarding this comment?

The problem seems to stem from (*Compiler).AddResource and (*Compiler).Compile() both requiring filenames / URLs though I have to admit I'm really more of a simple messenger here. I'd love to see OpenAPI 3.1 support in kin-openapi. :)

Thanks a bunch!
Cheers!

Possibility to compile to wasm?

Would it be possible to compile this library to WebAssembly for direct usage in the browser or elsewhere?
Unfortunately I don't know about requirements in Go for compilig to WASM as target..

Thanks!

Working example of in-memory JSON schema and in-memory JSON data to be validated against the schema

Lets say that I have in-memory schema defined as below:

var testJSONParamNonParamSchema = []byte(`
{
  "vmDeviceDefine": {
    "vm": {
      "additionalProperties": false, 
      "type": "object", 
      "required": [
        "vcpus"
      ], 
      "optional": [
        "memory"
      ], 
      "properties": {
        "vcpus": {
          "oneOf": [
            {
              "pattern": "^\\$[A-Za-z][-A-Za-z0-9_]*$", 
              "type": "string"
            }, 
            {
              "minimum": 2, 
              "type": "integer", 
              "maximum": 16, 
              "multipleOf": 2.0
            }
          ]
        },
        "memory": {
          "oneOf": [
            {
              "pattern": "^\\$[A-Za-z][-A-Za-z0-9_]*$", 
              "type": "string"
            }, 
            {
              "minimum": 512, 
              "type": "integer", 
              "maximum": 16384, 
              "multipleOf": 512
            }
          ]
        }
      }
    }
  }
}
`)

and JSON data (in-memory and not in a file) to be validated as below

var dataToBeValidatedAgainstSchema := `{"vm": {"vcpus": "$vcpus","memory": "$memory"}}`

How could I use this library to achieve the above? Is it possible? would be great if I could be pointed to an example on how to achieve the above?
THanks

Override LoadURL at Compiler

I'm implementing a feature that will allow schemas to be stored and updated; the details aren't very relevant, but the key point is that a schema URL may not have a globally-consistent referent (for instance, the current value vs one being updated). Thus, I'm finding the global LoadURL function to be limiting as a resolution strategy.

It seems like a simple solution would be to make the loader function local to the Compiler object (and initialized to the global). Does this change make sense? If so, I would be happy to send a PR.

Regex lookahead/behind is not supported

I have a regex like this:

"pattern": "^(?!(foo-|bar)-)[a-z][a-z0-9]+$"

In this example, I need to make sure a string does not start with foo- or bar-.

When I use this library, I get the error:
"^(?!(foo-|bar-))[a-z][a-z0-9]+$" is not valid "regex", which is valid regex for JS-based schema validators, but fails with this implementation, because the regexp library from the Golang stdlib does not support the ?!() syntax.

More info here:
https://stackoverflow.com/questions/26771592/negative-look-ahead-go-regular-expressions

panic when resolve #someid in other file

Hello, Santhosh Tekuri, may be I'm doing something wrong, but I got panic in Compile in this code:

	schema_d := `
{
    "type": "object",
    "properties": {
	"myid": { "type": "integer" },
	"otype": { "$ref": "defs.json#someid" }
    }
}
`
	defs_d := `
{
    "definitions": {
	"stt": {
	    "$schema": "http://json-schema.org/draft-07/schema#",
	    "$id": "#someid",
            "type": "object",
	    "enum": [ { "name": "stainless" }, { "name": "zinc" } ]
	}
    }
}
`
	instance_d := `
{
    "myid": 16,
    "otype": { "name": "zinc" }
}
`

	c := jsonschema.NewCompiler()
	c.Draft = jsonschema.Draft7

	schema_r := strings.NewReader(schema_d)
	c.AddResource("schema.json", schema_r)

	defs_r := strings.NewReader(defs_d)
	c.AddResource("defs.json", defs_r)

	schema, err := c.Compile("schema.json") //    <--- panic here
	if err != nil {
		log.Printf("compile: %v", err)
		return
	}

	instance_r := strings.NewReader(instance_d)
	err = schema.Validate(instance_r)
	if err != nil {
		log.Printf("validate: %v", err)
		return
	}

Question related to yamlText not having the declared property in schema text

Hi,
I am trying out the below and am expecting to see an error because the yamlText has a property "state" that is not defined in the schema text. Should I be expecting an error indicating "state" is not defined in schema? I want to be able to detect any properties that are not defined in schema but present in yamlText be indicated.

var yamlText = id: id1 name: joe state: married

var schemaText = { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": {"type": "string"} }, "required": ["id", "name"], "optional": ["status" ] }

func main() {
fmt.Println(schemaText)
var m interface{}
err := yaml.Unmarshal([]byte(yamlText), &m)
if err != nil {
panic(err)
}

compiler := jsonschema.NewCompiler()
//compiler.Draft = jsonschema.Draft4
if err := compiler.AddResource("schema.json", strings.NewReader(schemaText)); err != nil {
panic(err)
}
schema, err := compiler.Compile("schema.json")
if err != nil {
panic(err)
}
if err := schema.ValidateInterface(m); err != nil {
panic(err)
}

}

Panics are bad :(

Hi! Thanks for the great library!

I started changing datapackage-go to use jsonschema and stumbled upon a panic at jsonType. That might datapackage users to crash their program, which might not be what we want.

Would that be possible to remove it (returning an error or setting a default)?

Thanks!

Possibility to reference other parts of the document

With ajv I can reference other parts of the JSON document via the $data keyword.
Would that be possible with this library as well?
Or would it be possible to define it as a separate custom keyword, maybe?

thanks!

Trouble with conditionals

I am having a lot of trouble with using conditionals and I am not sure if it is my schema or a bug.

I have the property actions which has other properties who's keys are arbitrarily user defined.
The behavior I am trying to invoke for objects in actions is:

  • All objects are required to have the field action, meaning if we dont have it validation should fail.
  • If action is present, then I need one of the following:
    • if action = jump, then require property how_high
    • if action = sit, then require property where
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "actions": {
      "type":"object",
      "minProperties": 1,
      "patternProperties": {
        ".*":{
          "type":"object",
          "required": ["action"],
          "properties": {
            "action": {
              "type": "string"
            },
            "description": {
              "type": "string"
            }
          },
          "if":{
            "properties": { "action": {"type": "string"}}
          },
          "then": {
            "oneOf": [
              {
                "if": {
                  "properties": { "action": { "const": "jump" } }
                },
                "then": {
                  "properties": {
                    "how_high": { "type":"string"}
                  },
                  "required": ["how_high"]
                }
              },
              {
                "if": {
                  "properties": { "action": { "const": "sit" } }
                },
                "then": {
                  "required": ["where"],
                  "properties": {
                    "where":{ "type":"string" }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
}

This is the JSON I am trying to validate:

{
  "actions": {
    "jump_up1": {
      "action": "jump",
      "how_high": "very high"
    },
    "missing_action": {
      "description": "This should fail because we dont have action"
    },
    "sitdown": {
      "action": "sit",
      "where": "the floor"
    }
  }
}

However, this is the result I am getting:

I[#/actions] S[#/properties/actions] validation failed
  I[#/actions/jump_up1] S[#/properties/actions/patternProperties/.%2A/then] if-then failed
    I[#/actions/jump_up1] S[#/properties/actions/patternProperties/.%2A/then/oneOf] valid against schemas at indexes 0 and 1
  I[#/actions/missing_action] S[#/properties/actions/patternProperties/.%2A] validation failed
    I[#/actions/missing_action] S[#/properties/actions/patternProperties/.%2A/then] if-then failed
      I[#/actions/missing_action] S[#/properties/actions/patternProperties/.%2A/then/oneOf] oneOf failed
        I[#/actions/missing_action] S[#/properties/actions/patternProperties/.%2A/then/oneOf/0/then] if-then failed
          I[#/actions/missing_action] S[#/properties/actions/patternProperties/.%2A/then/oneOf/0/then/required] missing properties: "how_high"
        I[#/actions/missing_action] S[#/properties/actions/patternProperties/.%2A/then/oneOf/1/then] if-then failed
          I[#/actions/missing_action] S[#/properties/actions/patternProperties/.%2A/then/oneOf/1/then/required] missing properties: "where"
    I[#/actions/missing_action] S[#/properties/actions/patternProperties/.%2A/required] missing properties: "action"
  I[#/actions/sitdown] S[#/properties/actions/patternProperties/.%2A/then] if-then failed
    I[#/actions/sitdown] S[#/properties/actions/patternProperties/.%2A/then/oneOf] valid against schemas at indexes 0 and 1

Taking these one at a time:

  • Since missing_action does not have property action this, then should not be validating it
  • Since jump does not match sit, oneOf should only match index 0
  • Since sit does not match jump, oneOf should only match index 1

This is very baffling.

Extend user-defined keywords' context

I'm trying to define a keyword to validate uri-reference (e.g. for "data/client.json" make sure that client.json file exists and it is a valid json schema.
Current context for user-defined keyword contains only current data, without information about the current document. So it is not possible to validate the desired logic.
Do you think it is possible to extend the context with document location uri/document itself?
I can image that this can be useful for other validation types too.

JSON Extensions not working?

I just found your library and am trying to get a keyword extension working. I tried running the example provided in the docs: https://pkg.go.dev/github.com/santhosh-tekuri/jsonschema/v5#example-package-Extension

It doesn't look like it is working as intended. The Validate method always seems to call the default case... resulting in no validation being performed. The culprit is v is of type *strings.Reader when it should be a number.

I don't have any experience using this library so I am not sure if its a bug or the example is faulty.

func (s powerOfSchema) Validate(ctx jsonschema.ValidationContext, v interface{}) error {
	switch v.(type) {
	case json.Number, float64, int, int32, int64:
		fmt.Println("YES")
		pow := int64(s)
		n, _ := strconv.ParseInt(fmt.Sprint(v), 10, 64)
		for n%pow == 0 {
			n = n / pow
		}
		if n != 1 {
			return ctx.Error("powerOf", "%v not powerOf %v", v, pow)
		}
		return nil
	default:
		fmt.Println("switch.DEFAULT")
		return nil
	}
}

Adding json tags to Schema type

I would like to use the Schema type to programmatically generate the JSON schema itself.

Would you be open to accepting such an addition to the code?

Example:

type Schema struct {
	Location string `json:"location,omitempty"` // absolute location
.
.
.

Validation of unparsed JSON

The purpose of libraries like this is to ensure that some blob of JSON is valid to some schema. However, it seems that I need to provide an already-parsed object for the validation to work.

What I'm doing right now is:

        // Compile the schema to validate the request body with.
	schema, err := jsonschema.CompileString("schema.json", getJSONSchema())
	if err != nil {
            ......
	}

        // Parse the request body into an untyped map for validation.
	var unmarshalled map[string]interface{} 
	if err = json.Unmarshal(body, &unmarshalled); err != nil {
            ......
	}

        // Actually validate the request body.
	if err = schema.Validate(unmarshalled); err != nil {
            ......
        }

Which works, but only when the body to be validated is a JSON object. If I ever wanted to use an array or a primitive value then this would fail.

It would be useful if you could pass either string []byte or even io.Reader into schema.Validate and it do the right thing with it.

Cheers

Regression in "validation passed" output message

Previous versions of the jsonschema would validate a json file, and if there were no errors, would print out a timestamp and the message "Passed validation".

However, the current system no longer prints a message when validation is passed. It would be nice to obtain some form of notification that the schema was validated and actually passed, versus assuming that no output is a good thing.

Current behavior when validation passed:

Previous behavior when validation passed:
"HMIschemavalidator 2019/11/27 13:57:22 Passed validation"

Schema Stack is Private in Extension Compiler

In the extension compiler, I'd like to extract a path to the extension keyword in a particular schema. I think this could be achieved by accessing the schema stack in the CompilerContext, but the stack there is private. Is there some other method I'm missing? If not, would you be open to a PR to make it public or available via some other interface?

InvalidJSONTypeError.Error() should include unexpected value

A InvalidJSONTypeError error is returned when the schema validator encounters an unexpected type. In that case, the error includes the type, e.g. invalid jsonType: map[interface{}]interface{}; the value is not included in the error message.

It would be useful to show the unexpected value because it's not very obvious which part of the input document has the wrong type.

Steps to reproduce:

Create the following YAML document and validate against a JSON schema:

data := `
mapping:
   2: "abc"
   foo: "bar"
`
var inputYaml interface{}
yaml.Unmarshal(data, &inputYaml)
schema.ValidateInterface(inputYaml)

With the above document, yaml.Unmarshal() unmarshals the input data into a map[interface{}]interface{}. Looking at this minimalistic example, it's obvious that 2 should have been a string. But with larger input documents, it is harder to find the problem.
I think this can only happen when unmarshaling from yaml, not from JSON.

Proposed Solution

A basic improvement would be to include contextual information:

- panic(InvalidJSONTypeError(fmt.Sprintf("%T", v)))
+ panic(InvalidJSONTypeError(fmt.Sprintf("%T: %#v", v, v)))

make Schema fields public

Hi and thanks for this great package.

This is an enhancement or change request rather than a bug report:
Please consider making the jsonschema.Schema struct fields public to allow for post-processing the compiled Schema - I'm happy to attempt a PR.

More details on why this is required: .
We are working on a system where users can submit arbitrary JSON Schemas and then submit data that is validated against them. For our purposes we would like to limit some JSON Schema properties:

  • no usage of allOf, anyOf, oneOf, dependencies, not, additionalItems
  • additionalProperties must be false
  • type is always required and must be specified as string (single type, not set of types).
  • array must be of a single type, specified with: "items": { "type": "..." } etc.

We would also like to allow for backwards compatible schema updates which means validating one schema against another older one.

Thanks for your thoughts!

Format Not Validated

Given this schema.json:

{
    "type": "string",
    "format": "date-time"
}

And this bad.json:

"I am not a date-time"

jv does not complain about the invalid date-time:

$ ./cmd/jv/jv schema.json bad.json
$ echo $?
0

Shouldn't it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.