-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 91a3b96
Showing
4 changed files
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
api-raml/ | ||
article-json/ | ||
validate-article-json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module validate-article-json | ||
|
||
go 1.20 | ||
|
||
require github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 | ||
|
||
require ( | ||
github.com/kr/pretty v0.3.1 // indirect | ||
github.com/kr/text v0.2.0 // indirect | ||
github.com/rogpeppe/go-internal v1.9.0 // indirect | ||
github.com/tidwall/gjson v1.15.0 // indirect | ||
github.com/tidwall/match v1.1.1 // indirect | ||
github.com/tidwall/pretty v1.2.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | ||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= | ||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= | ||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= | ||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= | ||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= | ||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= | ||
github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw= | ||
github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= | ||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= | ||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= | ||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= | ||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= | ||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package main | ||
|
||
// "If you want a fast and correct validator, pick santhosh-tekuri/jsonschema." | ||
// - https://dev.to/vearutop/benchmarking-correctness-and-performance-of-go-json-schema-validators-3247 | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
"github.com/santhosh-tekuri/jsonschema/v5" | ||
"github.com/tidwall/gjson" | ||
) | ||
|
||
// todo: | ||
// https://json-schema.org/understanding-json-schema/reference/regular_expressions.html | ||
// https://github.com/santhosh-tekuri/jsonschema/issues/113 | ||
|
||
func panic_on_err(err error, action string) { | ||
if err != nil { | ||
panic(fmt.Sprintf("failed with '%s' while '%s'", err.Error(), action)) | ||
} | ||
} | ||
|
||
func slurp_bytes(path string) []byte { | ||
body, err := os.ReadFile(path) | ||
panic_on_err(err, "slurping bytes from path: "+path) | ||
return body | ||
} | ||
|
||
func fail(msg string) int { | ||
println(msg) | ||
return 1 | ||
} | ||
|
||
func success(msg string) int { | ||
println(msg) | ||
return 0 | ||
} | ||
|
||
type Foo struct { | ||
Label string | ||
Path string | ||
Schema *jsonschema.Schema | ||
} | ||
|
||
func main() { | ||
|
||
// parse args | ||
|
||
args := os.Args[1:] | ||
article_json_path := args[0] | ||
|
||
// configure validator | ||
|
||
loader := jsonschema.Loaders["file"] | ||
c := jsonschema.NewCompiler() | ||
c.Draft = jsonschema.Draft4 | ||
schema_file_list := map[string]string{ | ||
"POA": "api-raml/dist/model/article-poa.v3.json", | ||
"VOR": "api-raml/dist/model/article-vor.v7.json", | ||
} | ||
schema_map := map[string]Foo{} | ||
|
||
for label, path := range schema_file_list { | ||
rdr, err := loader(path) | ||
panic_on_err(err, fmt.Sprintf("loading '%s' schema file: ", label, path)) | ||
err = c.AddResource(label, rdr) | ||
panic_on_err(err, "adding schema to compiler: "+label) | ||
schema, err := c.Compile(label) | ||
panic_on_err(err, "compiling schema: "+label) | ||
schema_map[label] = Foo{ | ||
Label: label, | ||
Path: path, | ||
Schema: schema, | ||
} | ||
} | ||
|
||
// read article data and determine schema to use | ||
|
||
article_json_bytes := slurp_bytes(article_json_path) | ||
result := gjson.GetBytes(article_json_bytes, "article.status") | ||
if !result.Exists() { | ||
panic("'article.status' field in article data not found: " + article_json_path) | ||
} | ||
schema_key := strings.ToUpper(result.String()) // "poa" => "POA" | ||
schema, present := schema_map[schema_key] | ||
if !present { | ||
panic("schema not found: " + schema_key) | ||
} | ||
|
||
// article-json contains 'journal', 'snippet' and 'article' sections. | ||
// extract just the 'article' from the article data. | ||
|
||
result = gjson.GetBytes(article_json_bytes, "article") | ||
if !result.Exists() { | ||
panic("'article' field in article data not found: " + article_json_path) | ||
} | ||
// what is happening here?? we're extracting a slice of the matching bytes | ||
// from the article-json without converting it to a string then back to bytes. | ||
var raw []byte | ||
if result.Index > 0 { | ||
raw = article_json_bytes[result.Index : result.Index+len(result.Raw)] | ||
} else { | ||
raw = []byte(result.Raw) | ||
} | ||
|
||
// convert the article-json data into a simple go datatype | ||
var article interface{} | ||
err := json.Unmarshal(raw, &article) | ||
panic_on_err(err, "unmarshalling article section bytes") | ||
|
||
// finally, validate! | ||
|
||
start := time.Now() | ||
err = schema.Schema.Validate(article) | ||
if err != nil { | ||
os.Exit(fail("input file is not valid: " + err.Error())) | ||
} | ||
t := time.Now() | ||
elapsed := t.Sub(start) | ||
os.Exit(success(fmt.Sprintf("%s article validated in %s", schema.Label, elapsed))) | ||
} |