Want to Contribute to us or want to have 15k+ Audience read your Article ? Or Just want to make a strong Backlink?

Introduction to Cuelang – DEV Community ðŸ‘Đ‍ðŸ’ŧðŸ‘Ļ‍ðŸ’ŧ

I wager that at that second, you might be considering:

“One other programming language”?

Settle down, settle down, include me, and it’ll make sense 🙂

Not like different languages like Go or Rust, that are “general-purpose languages,” CUE has some explicit aims. Its identify is definitely an acronym that stands for “Configure Unify Execute,” and in line with the official documentation:

Though the language just isn’t a general-purpose programming language, it has many functions, similar to information validation, information templating, configuration, querying, code era, and even scripting.

It’s described as a “superset of JSON” and is closely impressed by Go. Or, as I prefer to assume:

“Think about that Go and JSON had a romance, and the fruit of that union was CUE” 😀

On this publish, I’ll current two situations the place the language can be utilized, however the official documentation has extra examples and an excellent quantity of knowledge to seek the advice of.



Validating information

The primary situation the place CUE excels is in information validation. It has native support for validating YAML, JSON, and Protobuf, amongst others.

I am going to use some examples of configuration files from the Traefik challenge, an API Gateway.

The next YAML defines a sound path to Traefik:

apiVersion: traefik.containo.us/v1alpha1
form: IngressRoute
metadata:
  identify: simpleingressroute
  namespace: default
spec:
  entryPoints:
    - net
  routes:
    - match: Host(`your.instance.com`) && PathPrefix(`/notls`)
      form: Rule
      companies:
        - identify: whoami
          port: 80
Enter fullscreen mode

Exit fullscreen mode

With this data, it’s doable to outline a brand new route in API Gateway, but when one thing is incorrect, we will trigger some issues. That is why it is important to have a simple method to detect points in configuration recordsdata like this. And that is the place CUE reveals its power.

Step one is to have the language put in on the machine. As I am utilizing macOS, I simply ran the command:

brew set up cue-lang/faucet/cue
Enter fullscreen mode

Exit fullscreen mode

Within the official documentation, you may see how one can set up it on different working techniques.

Now we will use the cue command to show this YAML right into a schema of the CUE language:

cue import traefik-simple.yaml
Enter fullscreen mode

Exit fullscreen mode

A file referred to as traefik-simple.cue is created with the contents:

apiVersion: "traefik.containo.us/v1alpha1"
form:       "IngressRoute"
metadata: {
    identify:      "simpleingressroute"
    namespace: "default"
}
spec: {
    entryPoints: [
        "web",
    ]
    routes: [{
        match: "Host(`your.example.com`) && PathPrefix(`/notls`)"
        kind:  "Rule"
        services: [{
            name: "whoami"
            port: 80
        }]
    }]
}
Enter fullscreen mode

Exit fullscreen mode

It is a literal translation from YAML to CUE, however let’s edit it to create some validation guidelines. The ultimate content material of traefik-simple.cue appears to be like like this:

apiVersion: "traefik.containo.us/v1alpha1"
form:       "IngressRoute"
metadata: {
    identify:      string
    namespace: string
}
spec: {
    entryPoints: [
        "web",
    ]
    routes: [{
        match: string
        kind:  "Rule"
        services: [{
            name: string
            port: >0 & <= 65535
        }]
    }]
}
Enter fullscreen mode

Exit fullscreen mode

A number of the objects had been precisely the identical, like apiVersion: "traefik.containo.us/v1alpha1" and form: "IngressRoute." Which means that these are the precise values anticipated in all recordsdata that might be validated by this schema. Any worth totally different from these might be thought of an error. Different data has modified, similar to:

metadata: {
    identify:      string
    namespace: string
}
Enter fullscreen mode

Exit fullscreen mode

On this snippet, we outline that the content material of identify, for instance, could be any legitimate string. Within the excerpt port: >0 & <= 65535, we outline that this subject can solely settle for a quantity between 0 and 65535.

It’s now doable to validate that the YAML content material conforms to the schema utilizing the command:

cue vet traefik-simple.cue traefik-simple.yaml
Enter fullscreen mode

Exit fullscreen mode

If all the pieces is appropriate, nothing is displayed on the command line. To show the way it works, I altered traefik-simple. yaml, altering the worth of port to 0. Then, when rerunning the command, you may see the error:

cue vet traefik-simple.cue traefik-simple.yaml
spec.routes.0.companies.0.port: invalid worth 0 (out of certain >0):
    ./traefik-simple.cue:16:10
    ./traefik-simple.yaml:14:18
Enter fullscreen mode

Exit fullscreen mode

If we alter any of the anticipated values, similar to form: IngressRoute to one thing totally different, similar to form: Ingressroute, the result’s a validation error:

cue vet traefik-easy.cue traefik-easy.yaml
form: conflicting values "IngressRoute" and "Ingressroute":
    ./traefik-easy.cue:2:13
    ./traefik-easy.yaml:2:8
Enter fullscreen mode

Exit fullscreen mode

This manner, discovering an error in a Traefik route configuration could be very simple. The identical could be utilized to different codecs like JSON, Protobuf, Kubernetes recordsdata, and many others.

I see an apparent situation of utilizing this information validation energy: including a step in CI/CDs to make use of CUE and validate configurations at construct time, avoiding issues within the deploy stage and utility execution. One other situation is so as to add the instructions in a hook of Git to validate the configurations within the improvement surroundings.

One other thrilling characteristic of CUE is the potential for creating packages, which comprise a collection of schemas that may be shared between tasks in the identical means as a package deal in Go. Within the official documentation, you may see how one can use this characteristic and a few native packages of the language, similar to strigs, lists, regex, and many others. We’ll use a package deal within the following instance.



Configuring functions

One other utilization situation for CUE is as an utility configuration language. Anybody who is aware of me is aware of I’ve no appreciation for YAML (to say the least), so every other possibility catches my eye. However CUE has some thrilling benefits:

  • As a result of it’s JSON-based, studying and writing are a lot less complicated (in my view)
  • Solves some JSON points like lacking feedback, which was a successful characteristic for YAML
  • As a result of it’s a full language, it’s doable to make use of if, loop, built-in packages, sort inheritance, and many others.

Step one for this instance was making a package deal to retailer our configuration. For that, I made a listing referred to as config, and inside it, a file referred to as config.cue with the content material:

package deal config 

db: {
    consumer:     "db_user"
    password: "password"
    host:     "127.0.0.1"
    port:     3306
}

metric: {
    host: "http://localhost"
    port: 9091
}

langs: [
    "pt_br",
    "en",
    "es",
]

Enter fullscreen mode

Exit fullscreen mode

The subsequent step was to create the appliance that reads the configuration:

package deal predominant

import (
    "fmt"

    "cuelang.org/go/cue"
    "cuelang.org/go/cue/load"
)

sort Config struct {
    DB struct {
        Person string
        Password string
        Host string
        Port int
    }
    Metric struct {
        Host string
        Port int
    }
    Langs []string
}

// LoadConfig hundreds the Cue config recordsdata, beginning within the dirname listing.
func LoadConfig(dirname string) (*Config, error) {
    cueConfig := &load.Config{
        Dir:        dirname,
    }

    buildInstances := load.Cases([]string{}, cueConfig)
    runtimeInstances := cue.Construct(buildInstances)
    occasion := runtimeInstances[0]

    var config Config
    err := occasion.Worth().Decode(&config)
    if err != nil {
        return nil, err
    }
    return &config, nil
}

func predominant() {
    c, err := LoadConfig("config/")
    if err != nil {
        panic("error studying config")
    }
    //a struct foi preenchida com os valores
    fmt.Println(c.DB.Host)
}

Enter fullscreen mode

Exit fullscreen mode

One benefit of CUE’s package deal idea is that we will break our configuration into smaller recordsdata, every with its personal performance. For instance, contained in the config listing, I break up config. Cue into separate recordsdata:

config/db.cue

package deal config 

db: {
    consumer:     "db_user"
    password: "password"
    host:     "127.0.0.1"
    port:     3306
}
Enter fullscreen mode

Exit fullscreen mode

config/metric.cue

package deal config 

metric: {
    host: "http://localhost"
    port: 9091
}
Enter fullscreen mode

Exit fullscreen mode

config/lang.cue

package deal config 

langs: [
    "pt_br",
    "en",
    "es",
]
Enter fullscreen mode

Exit fullscreen mode

And it was not crucial to alter something within the predominant.go file for the settings to be loaded. With this, we will higher separate the contents from the settings with out impacting the appliance code.



Conclusion

I simply “scratched the floor” of what is doable with CUE on this publish. It has been attracting attention and being adopted in tasks similar to Istio, which it makes use of to generate OpenAPI schemes and CRDs for Kubernetes and Dagger. It’s a instrument that may be very helpful for a number of tasks, primarily on account of its information validation energy. And as a substitute for YAML, for my private pleasure 😀

Initially printed at https://eltonminetto.dev on November 08, 2022.



Add a Comment

Your email address will not be published. Required fields are marked *

Want to Contribute to us or want to have 15k+ Audience read your Article ? Or Just want to make a strong Backlink?