Recently, I'm writing Rego(a query language to use in Open Policy Agent) every day and have decided to post some tricky syntaxes that took me a little time to understand.
In this post, I'm going to look at how to check if a key exists in an object in Rego.
I've pulled the sample code from the Policy Cheatsheet in the official docs.
has_key(x, k) { _ = x[k] }
Looks simple, but has a bit of a gotcha (at least for me) despite consuming the function is pretty intuitive (here's the playground):
has_key({"foo": "bar"}, "foo") # true
has_key({"foo": "bar"}, "baz") # undefined
It's checking if key k
exists in object x
. What confused me at first is _ = x[k]
. Why do we need the _ =
part?
Without the "_ ="
Let's see what happens if the function becomes like this:
has_key(x, k) { x[k] }
At first, this looks like it's working. But you have to think about the case where the value of x[k]
is actually false
.
The return value of the function is true
whenever the function body is satisfied. That is the case when x[k] unifies to anything that is not false
-- if x[k] unifies to false
, the function body is not satisfied... (functions are not very different from rules). Here's an example(and the playground):
has_key(x, k) { x[k] }
default foo_exists = false
foo_exists = has_key({"foo": false}, "foo") # false!!!
To avoid this unexpected behavior, the assigning(or union) part (_ =
) is mandatory.
With the "_ ="
Let's put the _ =
back inside the function.
has_key(x, k) { _ = x[k] }
With this, the function body is satisfied if it unifies -- i.e. there's an x[k], not undefined
-- but it doesn't matter if it's true
or false
, because the x[k] is put into a context where its value doesn't matter: _ = y
never fails, regardless of the value of y, as long as y is not undefined
.
Any other construct that doesn't regard the value would work as well. Here are some alternatives (which are not better, just different):
https://play.openpolicyagent.org/p/eed4f2wVGS
https://play.openpolicyagent.org/p/LgJo6T0tUz
Wrap up
Again, you can check the correct version in this playground.
If you're still uncomfortable with the Rego syntax used inside the function, check out the Policy Language#Variable Keys section in the official docs. Also, you can check the Policy Cheatsheet#Objects section.
Happy Rego coding!
P.S. I'd like to greatly appreciate @srenatus from the OPA community for reviewing my post and giving me accurate advice!
Top comments (1)
Hi Ken Fukuyama,
Thanks for this post. Do you know how to return true only if a key doesn't exists. Please check play.openpolicyagent.org/p/IliOo0XQG6, I am not able to achieve this. Thanks.