Lists
Lists in data, list parameters (stringList and numberList), and checking membership with in.
A list is a JSON array. Data can hold lists, and so can parameters: a stringList parameter holds
strings and a numberList parameter holds numbers. in checks whether a value is a member of a
list. When a list is a message argument, its elements are joined with ", ".
Syntax
params:
shippingCountries: { type: stringList, default: [DE, FR, ES] }
packSizes: { type: numberList, default: [1, 6, 12] }
# in a rule:
assert: { op: in, args: [{ var: data.country }, { var: params.shippingCountries }] }Example
The shop ships to three countries and sells packs of 1, 6 or 12. The request orders 5 bottles to Italy.
ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.lists, version: 1.0.0, title: "Lists" }
scope:
- { level: organization, id: learn }
entities:
Order:
schema: { $ref: "./learn.openapi.yaml#/components/schemas/Order" }
params:
shippingCountries:
type: stringList
default: [DE, FR, ES]
packSizes:
type: numberList
default: [1, 6, 12]
rules:
- id: order.country.shipped
kind: validation
target: { entity: Order, field: /country }
operations: [create]
assert: { op: in, args: [{ var: data.country }, { var: params.shippingCountries }] }
severity: error
finding: { code: LRN-LST-001, message: order.noShipping, args: { countries: { var: params.shippingCountries } } }
- id: order.quantity.pack
kind: validation
target: { entity: Order, field: /quantity }
operations: [create]
assert: { op: in, args: [{ var: data.quantity }, { var: params.packSizes }] }
severity: error
finding: { code: LRN-LST-002, message: order.packSize }
messages:
en:
order.noShipping: "We ship only to {countries}."
order.packSize: "Choose a pack of 1, 6 or 12."
tests:
- name: no shipping to Italy, and 5 is not a pack size
entity: Order
operation: create
given:
data: { country: IT, quantity: 5 }
expect:
decision: deny
findings:
- { rule: order.country.shipped, fields: [/country], message: "We ship only to DE, FR, ES." }
- { rule: order.quantity.pack, fields: [/quantity] }
- name: six bottles to Spain
entity: Order
operation: create
given:
data: { country: ES, quantity: 6 }
expect: { decision: allow, findings: [] }{
"entity": "Order",
"operation": "create",
"data": {
"country": "IT",
"quantity": 5
}
}Result, from the engine
Decisiondeny2 findings, server channel
LRN-LST-001errorblockingWe ship only to DE, FR, ES./countryLRN-LST-002errorblockingChoose a pack of 1, 6 or 12./quantity
Common mistakes
- Writing Norway as
NOwithout quotes. YAML 1.1 reads it asfalse. Write"NO". - Mixing types in a list:
incompares without coercion, so6is not in["6"]. - Writing a list literal in an expression (
[1, 6, 12]). A bare list is not an expression; use a parameter, or thelistoperator.
Exercise
Start shipping to Italy (IT). Check that an order of 6 to Italy is allowed and one to Portugal is
denied with the message "We ship only to DE, FR, ES, IT."
Hint
Only the default of shippingCountries changes. The message uses the list, so it changes by itself.
Show answer
ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.lists, version: 1.0.0, title: "Lists" }
scope:
- { level: organization, id: learn }
entities:
Order:
schema: { $ref: "./learn.openapi.yaml#/components/schemas/Order" }
params:
shippingCountries:
type: stringList
default: [DE, FR, ES, IT]
packSizes:
type: numberList
default: [1, 6, 12]
rules:
- id: order.country.shipped
kind: validation
target: { entity: Order, field: /country }
operations: [create]
assert: { op: in, args: [{ var: data.country }, { var: params.shippingCountries }] }
severity: error
finding: { code: LRN-LST-001, message: order.noShipping, args: { countries: { var: params.shippingCountries } } }
- id: order.quantity.pack
kind: validation
target: { entity: Order, field: /quantity }
operations: [create]
assert: { op: in, args: [{ var: data.quantity }, { var: params.packSizes }] }
severity: error
finding: { code: LRN-LST-002, message: order.packSize }
messages:
en:
order.noShipping: "We ship only to {countries}."
order.packSize: "Choose a pack of 1, 6 or 12."
tests:
- name: Italy is in the list now
entity: Order
operation: create
given:
data: { country: IT, quantity: 6 }
expect: { decision: allow, findings: [] }
- name: Portugal is not
entity: Order
operation: create
given:
data: { country: PT, quantity: 6 }
expect:
decision: deny
findings:
- { rule: order.country.shipped, message: "We ship only to DE, FR, ES, IT." }{
"entity": "Order",
"operation": "create",
"data": {
"country": "IT",
"quantity": 6
}
}Result, from the engine
Decisionallow0 findings, server channel