Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
lsh-0 committed Aug 2, 2023
0 parents commit 91a3b96
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
api-raml/
article-json/
validate-article-json
14 changes: 14 additions & 0 deletions go.mod
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
)
17 changes: 17 additions & 0 deletions go.sum
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=
125 changes: 125 additions & 0 deletions main.go
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)))
}

0 comments on commit 91a3b96

Please sign in to comment.