Skip to main content

Define, Validate, Generate with CUE language

"There is nothing so useless as doing efficiently that which should not be done at all." – Peter Drucker

cue language icon

In this article, I'll briefly explain how to use the CUE configuration language and how it might help you to keep consistent the YAML/JSON files by validating against the schema, reducing repetition, and many more.

Arguably, validation should be the foremost task of any configuration language. Most configuration languages, however, focus on boilerplate removal. CUE is different in that it takes the validation first stance. cuelang.org

Lets start from a simple example:

example.cue
// Schema
[string]: {
    name:  *"buddy" | string
    count: >=0 & <=100 | number
}

In the file example.cue we define the schema and the validation rules of our data. The schema states:

That's good, we've the schema of our data, let's check arbitrary YAML against the defined schema.

Here is an example of YAML, this example contains a bunch of errors related to the wrong value type:

example.yaml
item:
  name: []
  count: "110"

Let's use the cue vet command:

cue vet example.yaml example.cue
item.count: 2 errors in empty disjunction:
item.count: conflicting values "110" and >=0 (mismatched types string and number):
    ./example.cue:4:17
    ./example.cue:6:12
    ./example.yaml:3:11
item.count: conflicting values "110" and number (mismatched types string and number):
    ./example.cue:4:17
    ./example.cue:6:26
    ./example.yaml:3:11
item.name: 2 errors in empty disjunction:
item.name: conflicting values "buddy" and [] (mismatched types string and list):
    ./example.cue:5:13
    ./example.yaml:2:10
item.name: conflicting values string and [] (mismatched types string and list):
    ./example.cue:5:23
    ./example.yaml:2:10

As you can see there are many errors, is about conflicting values, the name value must be string, and "buddy" is not equal [] and so on. Lets fix our example.yaml

example.yaml
item:
  name: "teammate"
  count: 110

We've changed our example.yaml, run cue vet example.yaml example.cue and there are no errors, but what about the schema state >=0 & <=100 | number? The schema state is right, it denotes the value of the count key must be more or equal 0 and less or equal 100 or the number type, and in our last changes 110 is a number type.

Lets adjunct the schema a little to meet our requirements:

example.cue
// Schema
[string]: {
    name:  *"buddy" | string
    count: >=0 & <=100 & number // instead of '>=0 & <=100 | number'
}

Run cue vet again:

cue vet example.yaml example.cue
item.count: invalid value 110 (out of bound <=100):
    ./example.cue:6:18
    ./example.yaml:3:11

That's right.

Another things we can do is to move our data closer to schema and generate valid YAML/JSON.

Let's change example.cue a little:

example.cue
// Schema
[string]: {
    name:  *"buddy" | string
    count: >=0 & <=100 & number
}
// Data
example: {
  name: "somebody"
  count: 12
}

Now we able to generate a valid YAML/JSON from out data:

cue export example.cue --out yaml
example:
  name: somebody
  count: 12
cue export example.cue --out json
{
    "example": {
        "name": "somebody",
        "count": 12
    }
}

One of the cool things about CUE here is that it can infer default values for our data from the schema:

example.cue
// Schema
[string]: {
    name:  *"buddy" | string
    count: >=0 & <=100 & number
}
// Data
example: {
  count: 12
}

The code above generate next output:

cue export example.cue --out yaml
example:
  name: buddy
  count: 12

We're working a lot with different types of configurations, and on many occasions, that particular area is a mess, in most cases, the mess happens because of humans, somewhere you chose the wrong type of particular field or just forgot some key, it takes the time from us. There is no more precious thing in the world than time. In my opinion, the CUE can help here.

In this small article, I've scratched the surface of how CUE works and presented a small example with schema definition and data validation.

Happy coding!