-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs/howto: validate JSON using the Go API
This adds a guide demonstrating how to validate JSON data files against an embedded CUE schema. A YAML counterpart is requested in cue-lang/docs-and-content#150, as it was discovered during this change that the YAML equivalent couldn't be created simply by performing "s/json/yaml/g" on the source. Preview-Path: /docs/howto/validate-json-using-go-api/ Signed-off-by: Paul Jolly <[email protected]> Change-Id: I53c3112650f36a32b86a5d89f670f738d1b798c8 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cuelang.org/+/1194700 TryBot-Result: CUEcueckoo <[email protected]>
- Loading branch information
1 parent
4c3195c
commit e003529
Showing
4 changed files
with
442 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,169 @@ | ||
--- | ||
title: Validate JSON using the Go API | ||
tags: | ||
- go api | ||
- validation | ||
- encodings | ||
authors: | ||
- myitcv | ||
toc_hide: true | ||
--- | ||
|
||
This guide demonstrates how to write a Go program that validates JSON files | ||
using an embeded CUE schema. | ||
|
||
{{{with _script_ "en" "set caches to speed up re-running"}}} | ||
export GOMODCACHE=/caches/gomodcache | ||
export GOCACHE=/caches/gobuild | ||
{{{end}}} | ||
|
||
## Set up some schema and data files | ||
|
||
{{{with step}}} | ||
Create a CUE schema. | ||
|
||
You can use any schema that's relevant to your specific data, but our example uses this simple CUE: | ||
|
||
{{{with upload "en" "cue schema"}}} | ||
-- schema.cue -- | ||
#Schema: { | ||
name?: string | ||
age?: int | ||
} | ||
{{{end}}} | ||
{{{end}}} | ||
|
||
|
||
{{{with step}}} | ||
Create some known-good and known-bad test data. | ||
|
||
You may already have some representative test data. This data is relevant to our example schema: | ||
|
||
{{{with upload "en" "good data"}}} | ||
-- good.json -- | ||
{ | ||
"name": "Charlie Cartwright", | ||
"age": 80 | ||
} | ||
{{{end}}} | ||
|
||
{{{with upload "en" "bad data"}}} | ||
-- bad.json -- | ||
{ | ||
"name": [ | ||
"Moby", | ||
"Dick" | ||
], | ||
"age": "173" | ||
} | ||
{{{end}}} | ||
{{{end}}} | ||
|
||
{{{with step}}} | ||
Verify that your schema accepts and rejects your test data appropriately. | ||
|
||
Our example schema is contained in the `#Schema` definition, which we reference explicitly: | ||
|
||
{{{with script "en" "test schema"}}} | ||
cue vet schema.cue good.json -d '#Schema' | ||
! cue vet schema.cue bad.json -d '#Schema' | ||
{{{end}}} | ||
{{{end}}} | ||
|
||
## Create a Go program | ||
|
||
{{{with step}}} | ||
Initialize a Go module, or use an existing one if that's more suitable for your situation: | ||
|
||
{{{with script "en" "go mod init"}}} | ||
#ellipsis 0 | ||
go mod init go.example | ||
{{{end}}} | ||
{{{end}}} | ||
|
||
{{{with step}}} | ||
Create a main program. | ||
|
||
You can use this example code as a starting point: | ||
|
||
{{{with upload "en" "main go"}}} | ||
-- main.go -- | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
|
||
_ "embed" | ||
|
||
"cuelang.org/go/cue" | ||
"cuelang.org/go/cue/cuecontext" | ||
"cuelang.org/go/encoding/json" | ||
) | ||
|
||
// Embed our schema in a Go string variable. | ||
// | ||
//go:embed schema.cue | ||
var cueSource string | ||
|
||
func main() { | ||
ctx := cuecontext.New() | ||
|
||
// Build the schema | ||
schema := ctx.CompileString(cueSource).LookupPath(cue.ParsePath("#Schema")) | ||
|
||
// Load the JSON file specified (the program's sole argument) as a CUE value | ||
dataFilename := os.Args[1] | ||
dataFile, err := os.ReadFile(dataFilename) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
dataExpr, err := json.Extract(dataFilename, dataFile) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
dataAsCUE := ctx.BuildExpr(dataExpr) | ||
|
||
// Validate the JSON data using the schema | ||
unified := schema.Unify(dataAsCUE) | ||
if err := unified.Validate(); err != nil { | ||
fmt.Println("❌ JSON: NOT ok") | ||
log.Fatal(err) | ||
} | ||
|
||
fmt.Println("✅ JSON: ok") | ||
} | ||
{{{end}}} | ||
|
||
This example code embeds the CUE from `schema.cue` and uses it to validate a | ||
single JSON file, printing the validation result to its standard output stream. | ||
{{{end}}} | ||
|
||
{{{with step}}} | ||
Add a dependency on `cuelang.org/go` and ensure the Go module is tidy: | ||
{{{with script "en" "deps and tidy"}}} | ||
#ellipsis 0 | ||
go get cuelang.org/go@${CUELANG_CUE_LATEST} | ||
#ellipsis 0 | ||
go mod tidy | ||
{{{end}}} | ||
{{{end}}} | ||
|
||
## Run the Go program | ||
|
||
{{{with step}}} | ||
Verify that the Go program accepts and rejects your test data as expected: | ||
|
||
{{{with script "en" "verify go program"}}} | ||
go run . good.json | ||
! go run . bad.json | ||
{{{end}}} | ||
{{{end}}} | ||
|
||
## Related content | ||
|
||
- Go API: [`cue`](https://pkg.go.dev/cuelang.org/go/cue#section-documentation) -- package documentation | ||
- Go API: [`cue/cuecontext`](https://pkg.go.dev/cuelang.org/go/cue/cuecontext#section-documentation) -- package documentation | ||
- Go API: [`encoding/json`](https://pkg.go.dev/cuelang.org/go/encoding/json#section-documentation) -- package documentation | ||
- Tag: {{< tag "go api" >}} -- pages explaining and exploring CUE's Go API |
96 changes: 96 additions & 0 deletions
96
content/docs/howto/validate-json-using-go-api/gen_cache.cue
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,96 @@ | ||
package site | ||
{ | ||
content: { | ||
docs: { | ||
howto: { | ||
"validate-json-using-go-api": { | ||
page: { | ||
cache: { | ||
upload: { | ||
"cue schema": "ZpSJCm9G7J+MjuBIzc3pueaF87YCQpvv3hx5r8UwLLw=" | ||
"good data": "VxujqE1InR4iaC/qnP2xgIRqP1SFB8Khx9JCm/Z16Z8=" | ||
"bad data": "o7UoF2uK9CROfVxOPxkx6d58DoiGlhqxyWJsiLQw+pA=" | ||
"main go": "ZlWvRqx9OnyoDaf555iHnIXYgCPjz2igOpxpjyBF9Kc=" | ||
} | ||
multi_step: { | ||
hash: "7VTM00G63VNCUJDBFFR80NS40QASA7JSQLGC93V16BUTKK750VR0====" | ||
scriptHash: "D7AL3UDDJL6UIBJ1L3ASO3RB5JHESRQ6II1N9R88SETKGSR84LI0====" | ||
steps: [{ | ||
doc: "" | ||
cmd: "export GOMODCACHE=/caches/gomodcache" | ||
exitCode: 0 | ||
output: "" | ||
}, { | ||
doc: "" | ||
cmd: "export GOCACHE=/caches/gobuild" | ||
exitCode: 0 | ||
output: "" | ||
}, { | ||
doc: "" | ||
cmd: "cue vet schema.cue good.json -d '#Schema'" | ||
exitCode: 0 | ||
output: "" | ||
}, { | ||
doc: "" | ||
cmd: "cue vet schema.cue bad.json -d '#Schema'" | ||
exitCode: 1 | ||
output: """ | ||
age: conflicting values "173" and int (mismatched types string and int): | ||
./bad.json:6:12 | ||
./schema.cue:3:9 | ||
name: conflicting values string and ["Moby","Dick"] (mismatched types string and list): | ||
./bad.json:2:13 | ||
./schema.cue:2:9 | ||
""" | ||
}, { | ||
doc: "#ellipsis 0" | ||
cmd: "go mod init go.example" | ||
exitCode: 0 | ||
output: """ | ||
... | ||
""" | ||
}, { | ||
doc: "#ellipsis 0" | ||
cmd: "go get cuelang.org/[email protected]" | ||
exitCode: 0 | ||
output: """ | ||
... | ||
""" | ||
}, { | ||
doc: "#ellipsis 0" | ||
cmd: "go mod tidy" | ||
exitCode: 0 | ||
output: """ | ||
... | ||
""" | ||
}, { | ||
doc: "" | ||
cmd: "go run . good.json" | ||
exitCode: 0 | ||
output: """ | ||
✅ JSON: ok | ||
""" | ||
}, { | ||
doc: "" | ||
cmd: "go run . bad.json" | ||
exitCode: 1 | ||
output: """ | ||
❌ JSON: NOT ok | ||
main.go:42: #Schema.name: conflicting values string and ["Moby","Dick"] (mismatched types string and list) (and 1 more errors) | ||
exit status 1 | ||
""" | ||
}] | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
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 @@ | ||
package site | ||
|
||
content: docs: howto: "validate-json-using-go-api": page: _ |
Oops, something went wrong.