This guide demonstrates how to write a Go program that validates JSON files using an embeded CUE schema.

Set up some schema and data files

1

Create a CUE schema.

You can use any schema that’s relevant to your specific data, but our example uses this simple CUE:

schema.cue
#Schema: {
	name?: string
	age?:  int
}
2

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:

good.json
{
    "name": "Charlie Cartwright",
    "age": 80
}
bad.json
{
    "name": [
        "Moby",
        "Dick"
    ],
    "age": "173"
}
3

Verify that your schema accepts and rejects your test data appropriately.

Our example schema is contained in the #Schema definition, which we reference explicitly:

TERMINAL
$ cue vet schema.cue good.json -d '#Schema'
$ cue vet schema.cue bad.json -d '#Schema'
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

Create a Go program

4

Initialize a Go module, or use an existing one if that’s more suitable for your situation:

TERMINAL
$ go mod init go.example
...
5

Create a main program.

You can use this example code as a starting point:

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")
}

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.

6

Add a dependency on cuelang.org/go and ensure the Go module is tidy:

TERMINAL
$ go get cuelang.org/go@v0.12.0-0.dev.0.20241203164553-9f217e1d5fcc
...
$ go mod tidy
...

Run the Go program

7

Verify that the Go program accepts and rejects your test data as expected:

TERMINAL
$ go run . good.json
✅ JSON: ok
$ go run . bad.json
❌ 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
  • Go API: cue – package documentation
  • Go API: cue/cuecontext – package documentation
  • Go API: encoding/json – package documentation
  • Tag: go api – pages explaining and exploring CUE’s Go API