santhosh-tekuri / jsonschema

JSONSchema (draft 2020-12, draft 2019-09, draft-7, draft-6, draft-4) Validation using Go
Apache License 2.0
957 stars 98 forks source link

About using jsonschema.CompileString #98

Closed Zacama closed 1 year ago

Zacama commented 1 year ago

Hello, I have a question about using jsonschema: Why do I need to pass a URL parameter when calling CompileString?

santhosh-tekuri commented 1 year ago

the url you pass to CompileString gets used in error messages:

jsonschema.CompileString("schema.json", schemaString)
[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

in above error message you can see file:///Users/santhosh/jsonschema/schema.json

also in detailed and verbose output formats, the absoluteKeywordLocation property uses this url

then you might ask, why can't we just internally use some default say schema.json and do not ask user. there is one reason why we are not assuming some default uri. see explanation below:

jsonschema.CompileString(`{
    "type": "object",
    "properties": {
        "p": { "$ref": "schema.json" }
    }
}`)

assume that we have schema.json in current working directory. and in above code the user intension is the $ref to load schema.json from current working directory. But if we assume default uri of passed schema string as schema.json then the $ref resolves the schema string itself, instead of schema.json from current working directory.

I hope I am able to explain why you need to pass URL parameter to CompileString

Zacama commented 1 year ago

@santhosh-tekuri Thank you very much! I get it.

saward commented 6 months ago

What happens when that URL is a valid URL? E.g., if I do this:

    sch, err := jsonschema.CompileString("http://json-schema.org/schema", sampleSchema)

Then my json sample seems to pass my schema validation when it should fail. But if I introduce a typo, .orrg instead of .org, it fails validation against the schema contained in sampleSchema, as I expect:

    sch, err := jsonschema.CompileString("http://json-schema.orrg/schema", sampleSchema)

I'm wondering if this string is just for local error reporting, what's happening here? (v5.3.1).

santhosh-tekuri commented 6 months ago

it is treated as if the schema is downloaded from that url. for example if you have "$ref" with same url, then your schema is used in that place

saward commented 6 months ago

$ref is not used in the document at all. Are you able to help me understand why the behaviour of the validation changes when we go from http://json-schema.org/schema to http://json-schema.orrg/schema? Where the second one works as expected, but the first does not.

Here's a minimal sample (https://go.dev/play/p/P7RqtVbTT_e), where schema2 fails as expected but schema1 passes:

package main

import (
    "encoding/json"
    "log"

    "github.com/santhosh-tekuri/jsonschema/v5"
)

var sampleSchema string = `{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer"
    },
    "name": {
      "type": "string"
    }
  },
  "required": ["id", "name"]
}`

var sampleJSON string = `{
  "id": 456
}`

func main() {
    schema1, err := jsonschema.CompileString("http://json-schema.org/schema", sampleSchema)
    if err != nil {
        log.Fatalf("%#v", err)
    }

    schema2, err := jsonschema.CompileString("http://json-schema.orrg/schema", sampleSchema)
    if err != nil {
        log.Fatalf("%#v", err)
    }

    var v interface{}
    if err := json.Unmarshal([]byte(sampleJSON), &v); err != nil {
        log.Fatalf("%#v", err)
    }

    if err = schema1.Validate(v); err != nil {
        log.Printf("Failed validation against schema 1: %s\n", err)
    }

    if err = schema2.Validate(v); err != nil {
        log.Printf("Failed validation against schema 2: %s\n", err)
    }
}

Output:

2024/05/23 12:52:19 Failed validation against schema 2: jsonschema: '' does not validate with http://json-schema.orrg/schema#/required: missing properties: 'name'
santhosh-tekuri commented 6 months ago

@saward From the example, it is easier to understand your question.

CompleString internally calls Compiler.AddResourceJson. i.e we are adding a resource for given url and content.

standard meta schemas are treated superior to use added resources and get precedence always. in your case "http://json-schema.org/schema" refers to latest metaschema. so CompileString is actually ignoring the string you have given and actually compiling draft 2020-12 metaschema.

when you make a spell mistake, then it longer matches with any standard metaschema, so it is actually compiling the schemaString you have given.