Rule Cascade
LearnIntroduction

Your first rule in 2 minutes

Write one validation rule, send one request, read the decision.

A ruleset is a YAML file. It names the data it checks and holds rules. A validation rule checks one thing. When its assert is false, the engine reports a finding, and an error finding denies the request.

Syntax

the shape of a validation rule
- id: <rule id>
  kind: validation
  target: { entity: <Entity>, field: /<field> }
  operations: [create]
  assert: <expression that must be true>
  severity: error
  finding: { code: <CODE>, message: <message key> }

Example

This rule allows at most 10 items per order. The request orders 11.

first-rule.ruleset.yaml
ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.first-rule, version: 1.0.0, title: My first rule }
scope:
  - { level: organization, id: learn }
entities:
  Order:
    schema: { $ref: "./learn.openapi.yaml#/components/schemas/Order" }
rules:
  - id: order.quantity.max
    kind: validation
    target: { entity: Order, field: /quantity }
    operations: [create]
    assert: { op: lte, args: [{ var: data.quantity }, 10] }
    severity: error
    finding: { code: LRN-ORD-001, message: order.tooMany }
messages:
  en:
    order.tooMany: "You can order at most 10 items."
tests:
  - name: eleven items are denied
    entity: Order
    operation: create
    given:
      data: { quantity: 11 }
    expect:
      decision: deny
      findings:
        - { rule: order.quantity.max, fields: [/quantity] }
  - name: ten items are allowed
    entity: Order
    operation: create
    given:
      data: { quantity: 10 }
    expect: { decision: allow, findings: [] }
The entity schema, learn.openapi.yaml (the same for every lesson)
learn.openapi.yaml
openapi: 3.1.0
info: { title: Learn Rule Cascade, version: 1.0.0 }
paths: {}
components:
  schemas:
    Order:
      type: object
      properties:
        id: { type: string }
        quantity: { type: integer }
        price: { type: number }
        total: { type: number }
        discount: { type: number }
        shipping: { type: number }
        coupon: { type: string }
        email: { type: string }
        country: { type: string }
        status: { type: string }
        express: { type: boolean }
        giftWrap: { type: boolean }
        giftMessage: { type: string }
        notes: { type: string }
        reference: { type: string }
        orderDate: { type: string }
        deliveryDate: { type: string }
        paymentMethod: { type: string }
        cardNumber: { type: string }
        currency: { type: string }
        weight: { type: number }
        priority: { type: integer }
        approved: { type: boolean }
        cancelReason: { type: string }
        promoCodes: { type: array, items: { type: string } }
        scores: { type: array, items: { type: number } }
        tags: { type: array, items: { type: string } }
        items:
          type: array
          items:
            type: object
            properties:
              sku: { type: string }
              qty: { type: integer }
              price: { type: number }
    Customer:
      type: object
      properties:
        id: { type: string }
        name: { type: string }
        nickname: { type: string }
        email: { type: string }
        backupEmail: { type: string }
        phone: { type: string }
        country: { type: string }
        dateOfBirth: { type: string }
        vatId: { type: string }
        company: { type: string }
        accountType: { type: string }
        newsletter: { type: boolean }
        tier: { type: string }
        age: { type: integer }
        website: { type: string }
        postcode: { type: string }
        username: { type: string }
        iban: { type: string }
        bio: { type: string }
        signupDate: { type: string }
        lastLogin: { type: string }
        creditLimit: { type: number }
        balance: { type: number }
        verified: { type: boolean }
        roles: { type: array, items: { type: string } }
        address:
          type: object
          properties:
            street: { type: string }
            city: { type: string }
            postcode: { type: string }
            country: { type: string }
        contacts:
          type: array
          items:
            type: object
            properties:
              name: { type: string }
              email: { type: string }
              phone: { type: string }
    Ticket:
      type: object
      properties:
        id: { type: string }
        title: { type: string }
        description: { type: string }
        status: { type: string }
        priority: { type: string }
        assignee: { type: string }
        reporter: { type: string }
        dueDate: { type: string }
        createdAt: { type: string }
        closedAt: { type: string }
        resolution: { type: string }
        estimate: { type: number }
        labels: { type: array, items: { type: string } }
request.json
{
  "entity": "Order",
  "operation": "create",
  "data": {
    "quantity": 11
  }
}

Result, from the engine

Decisiondeny1 finding, server channel

  • LRN-ORD-001errorblockingYou can order at most 10 items./quantity
Try it YourselfOpens this ruleset and request in the playground. Nothing to install.

Exercise

Change the rule so that an order may have at most 5 items. Check it with a request of 6 items.

Hint

Change the number 10 in the assert and in the message. Then change the request.

Show answer
first-rule.ruleset.yaml
ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.first-rule, version: 1.0.0, title: My first rule }
scope:
  - { level: organization, id: learn }
entities:
  Order:
    schema: { $ref: "./learn.openapi.yaml#/components/schemas/Order" }
rules:
  - id: order.quantity.max
    kind: validation
    target: { entity: Order, field: /quantity }
    operations: [create]
    assert: { op: lte, args: [{ var: data.quantity }, 5] }
    severity: error
    finding: { code: LRN-ORD-001, message: order.tooMany }
messages:
  en:
    order.tooMany: "You can order at most 5 items."
tests:
  - name: six items are denied
    entity: Order
    operation: create
    given:
      data: { quantity: 6 }
    expect:
      decision: deny
      findings:
        - { rule: order.quantity.max, message: You can order at most 5 items. }
  - name: five items are allowed
    entity: Order
    operation: create
    given:
      data: { quantity: 5 }
    expect: { decision: allow, findings: [] }
request.json
{
  "entity": "Order",
  "operation": "create",
  "data": {
    "quantity": 6
  }
}

Result, from the engine

Decisiondeny1 finding, server channel

  • LRN-ORD-001errorblockingYou can order at most 5 items./quantity
Course overview

On this page