シナプス技術者ブログ

シナプスの技術者公式ブログ。インターネットで、鹿児島の毎日を笑顔にします。

CUE言語入門

シナプスの技術部システム開発課の小園です。
CUE言語をとあるきっかけでさわってみました。

CUE言語とは

設定記述言語です。
テキストベースのデータの定義、検証などができます。
(JSONやYAMLのようなデータ定義の仕様です。)
CUE Playgroundというブラウザで実行可能なツールがあるので、簡単に試す事ができます。

DaggerというCI/CDツールが気になって見てみた時に設定記述言語として採用されていたため、その存在を知りました。
(この記事内ではDaggerの紹介はリンクのみにします。)

コマンドラインツールのインストール

CUE言語にはコマンドラインツールがあります。
コマンドラインツールを使う事で、データの検証や、CUEファイルからJSON/YAMLへの変換などができます。
インストールはHomebrewを使える環境であればHomebrewから、それ以外は公式サイトよりバイナリファイルをダウンロードして展開、配置をします。
詳細は公式マニュアルを参照ください。

CUEファイルの記述例

簡単なCUEファイルサンプルを用意しました。

# cat person.cue
// Person Bob
Bob: {name: "Bob", age: 28, sex: "male"}

// Person Alice
Alice: {
        name: "Alice"
        age:  27
        sex:  "female"
}

CUEファイルの評価をします。
記述内容に問題があれば、エラーが出ます。

# cue eval person.cue
Bob: {
    name: "Bob"
    age:  28
    sex:  "male"
}
Alice: {
    name: "Alice"
    age:  27
    sex:  "female"
}

JSONで出力する事もできます。
慣れ親しんだJSONにする事でCUEファイルの定義がどのような内容か判ります。

# cue eval person.cue --out json
{
    "Bob": {
        "name": "Bob",
        "age": 28,
        "sex": "male"
    },
    "Alice": {
        "name": "Alice",
        "age": 27,
        "sex": "female"
    }
}

CUE言語の特徴

サンプルの内容から、以下のようなことが挙げられます。

  • CUEファイル内にコメントを入れる事が可能。
  • フィールドの最後のカンマが不要。
  • 外側のカッコの省略が可能。
  • CUEファイルを操作するためのコマンドラインツール(cue)が提供されている。
  • JSON/YAMLでの出力が可能。

他にも、以下のような事が可能です。

  • スキーマ定義が書け、検証が可能。
  • JSON/YAMLからCUE言語への変換が可能。
  • 環境による設定記述内容の出し分けが可能。

デメリットとして以下のようなことが挙げられます。

  • マイナーである。
    • ドキュメントはそろっているので、実利用上は問題は無い。
  • パーサー実装がまだ少ない。
    • メインの設定ファイルとしては使い難い。
    • 実装があるのは、Go言語位。

JSON/YAMLとの違い

JSONとの違い

JSONと比較した場合の優位点は以下のようになります。

  • JSONは末尾カンマを適切に処理する必要があるが、CUE言語は不要である場合が多い。

YAMLとの違い

YAMLと比較した場合の優位点は以下のようになります。

  • YAMLはインデントを正確に記述する必要があるが、CUE言語にはインデントを気にする必要はない。

スキーマ定義

スキーマ定義を含むCUEファイルは以下のようになります。

# cat person.cue
// Person定義
#Person: {
        name: string
        age:  int & >=0 & <=120
        sex:  string & "male" | "female"
}

// Person Bob
Bob: #Person
Bob: {name: "Bob", age: 28, sex: "male"}

// Person Alice
Alice: #Person
Alice: {
        name: "Alice"
        age:  27
        sex:  "female"
}

#から始まる箇所でスキーマ定義をしています。
検証をし、JSONで出力します。
エラーが無く、JSONが出力され、検証をされたことがわかります。
(検証でエラーになった場合には、JSONは出力されません。)

# cue eval person.cue --out json
{
    "Bob": {
        "name": "Bob",
        "age": 28,
        "sex": "male"
    },
    "Alice": {
        "name": "Alice",
        "age": 27,
        "sex": "female"
    }
}

環境による設定記述内容の出し分け

CUEファイル以下のように記載します。

# cat person.cue
_env: "prd" | "stg" | "dev" @tag(env)

// Person定義
#Person: {
        name: string
        age:  int & >=0 & <=120
        sex:  string & "male" | "female"
        role: *"staff" | string
}

// Person Bob
Bob: #Person
Bob: {name: "Bob", age: 28, sex: "male"}

// Person Alice
Alice: #Person
Alice: {
        name: "Alice"
        age:  27
        sex:  "female"
        if _env == "dev" {
                role: "admin"
        }
}

roleはデフォルト値がstaffである設定がされていますが、途中のif文で変数_envの値がdevの場合には、roleがadminとなるようにしています。
cueコマンドより変数_envをdevと定義して、JSONを作成します。
意図したとおりに、Aliceのroleがadminになっています。

# cue eval -t env=dev person.cue --out=json
{
    "Bob": {
        "name": "Bob",
        "age": 28,
        "sex": "male",
        "role": "staff"
    },
    "Alice": {
        "name": "Alice",
        "age": 27,
        "sex": "female",
        "role": "admin"
    }
}

変数_envの値をstgとしてJSONを作成します。
意図したとおりに、Aliceのroleはstaffになっています。

# cue eval -t env=stg person.cue --out=json
{
    "Bob": {
        "name": "Bob",
        "age": 28,
        "sex": "male",
        "role": "staff"
    },
    "Alice": {
        "name": "Alice",
        "age": 27,
        "sex": "female",
        "role": "staff"
    }
}

まとめ

CUE言語は既存の設定記述言語(JSON/YAML)の問題点を解決できています。
ですが、CUE言語をメインとして使うには、周辺環境(パーサーなど)が整っていません。
一方で、JSONやYAMLファイルを柔軟に出力する手段としては有効です。
環境によって設定内容を書き換える場合などの場合には手段の候補になり得ます。