Skip to content

Protocol Buffers#

CEL can work directly with Protocol Buffer messages and enumerations. Message types and enumeration values are referenced by their fully qualified names.

Examples on this page use this Protobuf definition:

syntax = "proto3";

package example.v1;

message User {
  string name = 1;
  Role role = 2;
  repeated string tags = 3;
  Address address = 4;
  map<string, string> labels = 5;
}

message Address {
  string city = 1;
}

enum Role {
  ROLE_UNSPECIFIED = 0;
  ROLE_VIEWER = 1;
  ROLE_EDITOR = 2;
  ROLE_ADMIN = 3;
}

Literals#

Create message literals using the fully qualified type name.

example.v1.User{name: "Alice"}
// result: {"name":"Alice"} (example.v1.User)

Reference enumeration values by their fully qualified name. All enumerations are integers; there are no enumeration types in CEL.

example.v1.Role.ROLE_ADMIN
// result: 3 (int)

Field access#

Access message fields using dot notation. Index notation is not supported for messages; avoid field names that conflict with CEL reserved words.

// input: user = example.v1.User{name: "Alice"}
user.name
// result: "Alice" (string)
// input: user = example.v1.User{address: example.v1.Address{city: "London"}}
user.address.city
// result: "London" (string)

Field presence#

has() checks whether a field is set, following Protocol Buffer field presence rules.

// input: user = example.v1.User{name: "Alice"}
has(user.name)
// result: true (bool)
// input: user = example.v1.User{}
has(user.address) ? user.address.city : "unknown"
// result: "unknown" (string)

Default values#

Unset fields return their default values.

// input: user = example.v1.User{}
user.name
// result: "" (string)
// input: user = example.v1.User{}
user.address
// result: {} (example.v1.Address)
// input: user = example.v1.User{}
user.address.city
// result: "" (string)
// input: user = example.v1.User{}
user.tags
// result: [] (list)
// input: user = example.v1.User{}
user.labels
// result: {} (map)
// input: user = example.v1.User{}
user.role == example.v1.Role.ROLE_UNSPECIFIED
// result: true (bool)

Comparison#

Messages support equality comparison. Two messages are equal if they have the same type and all fields are equal, following Protocol Buffer field presence semantics.

example.v1.User{name: "Alice"} == example.v1.User{name: "Alice"}
// result: true (bool)
example.v1.User{name: "Alice"} == example.v1.User{name: "Bob"}
// result: false (bool)

Enumeration fields can be compared to the fully qualified constants or integer literals.

// input: user = example.v1.User{name: "Alice", role: example.v1.Role.ROLE_ADMIN}
user.role == example.v1.Role.ROLE_ADMIN
// result: true (bool)
// input: user = example.v1.User{name: "Alice", role: example.v1.Role.ROLE_ADMIN}
user.role == 3
// result: true (bool)
// input: user = example.v1.User{name: "Alice", role: example.v1.Role.ROLE_EDITOR}
user.role in [example.v1.Role.ROLE_EDITOR, example.v1.Role.ROLE_ADMIN]
// result: true (bool)

See also#

  • Maps - Key-value collections and JSON objects
  • Lists - Repeated fields behave like lists
  • Time - Timestamps and durations