Skip to main content

Rego Keyword: if

The if keyword is used when defining rules in Rego. if separates the rule head from the rule body, making it clear which part of the rule is is the condition (the part following the if).

The keyword is also use to make the policy rules written in Rego easier to read by being more 'English-like'. For example:

rule := "some value" if some_condition

Examples

Defining simple rules

Most commonly, if is used to create boolean rules where if any rule head is true, then the whole rule is true. In this simple example, when both:

  • the input.role field is present,
  • and set to the value of "admin"

Then, the allow rule will be true. If either of these conditions is not met, the rule will be false.

policy.rego
package play

import rego.v1

allow if input.role == "admin"

allow if {
path[0] == "users"
path[1] == input.user_id
}
input.json
{
"role": "admin",
"path": [
"payments",
"approve"
]
}
data.json
{}

Open in OPA Playground

RuleOutput Value
allowtrue

Defining multi-value rules

The if keyword is used for all rules though, including rules that create objects and sets.

policy.rego
package play

import rego.v1

# missing_paths creates a set missing input paths
missing_paths contains path if {
some path in data.required_paths

parts := split(path, ".")

object.get(input, parts, "") == ""
}

# validations is a mapping of input paths to error messages
validations[path] contains "path must be set" if {
some path, _ in missing_paths
}

# role and email have additional validation rules
validations.role contains "role cannot be blank" if {
input.role == ""
}

validations.email contains message if {
not endswith(input.email, "@example.com")

message := sprintf("email %s must end with @example.com", [input.email])
}
input.json
{
"roles": [
"admin"
],
"email": "admin@example.net",
"request": {
"headers": {},
"path": "/v1/payments"
}
}
data.json
{
"required_paths": [
"request.method",
"request.path",
"request.headers",
"role",
"email"
]
}

Open in OPA Playground

RuleOutput Value
validations{"email":["email admin@example.net must end with @example.com"],"request.method":["path must be set"],"role":["path must be set"]}

Defining functions

if is also used in functions. Much like rules, in Rego functions can have one or more heads. The head and body of a function are also separated by the if keyword for consistency and readability.

In this example, we can see that the is_sudo function is incrementally defined where each head adds new cases to the functionality. In this case, each head defines scenarios where the user is a 'sudoer' - both when the user is an admin or when the user has the sudo field set.

policy.rego
package play

import rego.v1

default is_sudo(_) := false

is_sudo(user) if {
user.role == "admin"
}

is_sudo(user) if {
user.sudo == true
}

allow if is_sudo(input.user)
input.json
{
"user": {
"sudo": false
}
}
data.json
{}

Open in OPA Playground

RuleOutput ValueNotes
allowundefinedSince there is no default for allow, it is undefined.

When if is not used

if is everywhere in Rego, but there are some cases where we don't use it.

data.json
{}
input.json
{}
policy.rego
package play

default allow := false # not in default cases

my_constant := 42 # not for constants

# not for rule names
if {
input.admin
}

allow if {
# not inside rules
input.admin if input.roles.admin == true
}

Further Reading

Below are some links that provide more information about the if keyword:

  • If you are interested in learning about why if was added to Rego, see the notes in the OPA v1.0 documentation.
  • Read the release notes from when the if keyword was added to Rego in OPA v0.42.0.
  • Using if is also recommended by Regal.