A JSON-based rules engine in Go.
This can be used to store configuration data when you require something more dynamic than a static key/value mapping. Feature flags are one use case for something like this.
For example, let's say you just added a new feature to your application. This may have been a very complex feature and you would like to only show it to a subset of your users at first to make sure that everything is working correctly. For such a situation, you may create a rule like this:
{
"eq": [
{ "context": "beta" },
true
]
}
This rule evaluates to true if the context passed in has a beta
value of true.
$ ./toga eval -rule '{"eq": [{"context": "beta"}, true]}' -context '{"beta": true}'
true
$ ./toga eval -rule '{"eq": [{"context": "beta"}, true]}' -context '{"beta": false}'
false
You can also use if/then logic in your rules and return things other than booleans.
$ ./toga eval -rule '{"if": {"condition": {"gt": { "first": {"context": "accountAge"}, "second": 365.0 }}, "then": "Hello, old friend!", "else": "Welcome, new friend!" } }' -context '{"accountAge": 400.0}'
"Hello, old friend!"
$ ./toga eval -rule '{"if": {"condition": {"gt": { "first": {"context": "accountAge"}, "second": 365.0 }}, "then": "Hello, old friend!", "else": "Welcome, new friend!" } }' -context '{"accountAge": 12.0}'
"Welcome, new friend!"
Sometimes, you may want to read a rule from a file instead of specifying it directly as a string. To do so, you can use the rule-file
parameter like so:
$ cat << EOF >> rule.json
{
"if": {
"condition": {
"gt": {
"first": {"context": "accountAge"},
"second": 365.0
}
},
"then": "Hello, old friend!",
"else": "Welcome, new friend!"
}
}
EOF
$ ./toga eval -rule-file rule.json -context '{"accountAge": 12.0}'
"Welcome, new friend!"
$ ./toga eval -rule-file rule.json -context '{"accountAge": 999.0}'
"Hello, old friend!"
You can manage your rule files using consul-template to distribute your dynamic configurations across your infrastructure.
See the guide here for instructions on settings up consul-template and consul. Once you have this setup, you can create and use a template file for a rule file like so:
$ cat << EOF >> rule-a.tpl
{{ key "/rule_a" }}
EOF
$ ./consul-template -template rule-a.tpl:rule-a.json
# Return true if accountAge > 365
$ consul kv put rule_a '{ "gt": { "first": { "context": "accountAge" }, "second": 365.0 } }'
$ ./toga eval -rule-file rule.json -context '{"accountAge": 300.0}'
false
# Lower the accountAge threshold
$ consul kv put rule_a '{ "gt": { "first": { "context": "accountAge" }, "second": 250.0 } }'
$ ./toga eval -rule-file rule.json -context '{"accountAge": 300.0}'
true
To use this library within your Go code, the main interface is in the sdk package. The functionality is exposed through the EvalRuleFile
function. See the todo-list application for a full working example.
See the examples folder for some usage examples.