Runtime expressions

By Phil Sturgeon
Last update on February 01, 2025

Runtime expressions are the heart of Arazzo’s dynamic capabilities. They allow you to reference data from inputs, previous steps, and responses, compute new values, and create conditional logic. Understanding runtime expressions is essential for building sophisticated workflows.

What are runtime expressions? #

Runtime expressions are evaluated during workflow execution to produce values. They start with a $ and use dot notation to access data:

# Reference workflow input
$inputs.origin

# Reference previous step output
$steps.search.outputs.tripId

# Reference response status
$statusCode

# Reference response body (The body payload needs to be accessed with a JSON pointer)
$response.body#/booking/id

Expression contexts #

Expressions can reference data from several contexts:

Workflow inputs #

Access data passed to the workflow:

workflows:
  - workflowId: search-trips
    inputs:
      type: object
      properties:
        origin:
          type: string
        destination:
          type: string
        date:
          type: string
    
    steps:
      - stepId: search
        parameters:
          - name: from
            in: query
            value: $inputs.origin  # Access workflow input
          - name: to
            in: query
            value: $inputs.destination
          - name: departure
            in: query
            value: $inputs.date

Nested inputs:

inputs:
  type: object
  properties:
    passenger:
      type: object
      properties:
        name:
          type: string
        age:
          type: integer

# Access nested values
value: $inputs.passenger.name
value: $inputs.passenger.age

Array inputs:

inputs:
  type: array
  items:
    properties:
      userName:
        type: string
      email:
        type: string

# Access input properties
value: $inputs[0].userName
value: $inputs[0].email

Previous step outputs #

Reference outputs from earlier steps:

steps:
  - stepId: search
    operationId: $sourceDescriptions.api.searchTrips
    outputs:
      selectedTripId: $response.body#/trip/id
      tripPrice: $response.body#/trip/price
  
  - stepId: createBooking
    operationId: $sourceDescriptions.api.createBooking
    requestBody:
      payload:
        # Reference outputs from 'search' step
        tripId: $steps.search.outputs.selectedTripId
        price: $steps.search.outputs.tripPrice

To access an output from a previous step, use the syntax:

$steps.{stepId}.outputs.{outputName}

For this to work the output must be defined in the referenced step, and that step must have already run.

Learn more about steps and outputs.

Current response #

Within success/failure criteria and outputs, access the current response:

- stepId: getBooking
  operationId: $sourceDescriptions.api.getBooking
  successCriteria:
    # Access response body
    - condition: $response.body#/status == 'confirmed'

    # Access response headers
    - condition: $response.header.content-type == 'application/json'

  outputs:
    # Extract from response
    bookingId: $response.body#/id
    customerEmail: $response.body#/customer/email
    total: $response.body#/pricing/total

Response properties:

HTTP status #

Access the HTTP status code of the current response:

successCriteria:
  - condition: $statusCode >= 200 && $statusCode < 300

outputs:
  responseCode: $statusCode

Source descriptions #

Reference operations from source APIs:

sourceDescriptions:
  - name: trainApi
    url: ./train-api.yaml
    type: openapi

steps:
  - stepId: search
    # Reference operation from source
    operationId: $sourceDescriptions.trainApi.searchTrips

That’s $sourceDescriptions.{sourceName}.{operationId} or $sourceDescriptions.{sourceName}.{workflowId} for other Arazzo workflows.

Operators in conditions #

Runtime expressions support various operators for use in success and failure criteria:

Comparison operators #

successCriteria:
  # Equality
  - condition: $response.body#/status == 'confirmed'
  - condition: $statusCode == 200
  
  # Inequality
  - condition: $response.body#/error != null
  - condition: $statusCode != 404
  
  # Greater than
  - condition: $response.body#/price > 100
  - condition: $response.body#/stock > $inputs.quantity
  
  # Greater than or equal
  - condition: $response.body#/rating >= 4.0
  
  # Less than
  - condition: $response.body#/price < $inputs.maxPrice
  
  # Less than or equal
  - condition: $response.body#/quantity <= $response.body#/maxQuantity

Logical operators #

successCriteria:
  # AND - all conditions must be true
  - condition: $statusCode == 200 && $response.body#/available == true
  - condition: $response.body#/price > 0 && $response.body#/price < 1000
  
  # OR - at least one condition must be true
  - condition: $statusCode == 200 || $statusCode == 201
  - condition: $response.body#/status == 'confirmed' || $response.body#/status == 'pending'

String operators #

Concat strings using interpolation:

outputs:
  fullName: '{$response.body#/firstName} {$response.body#/lastName}'
  message: 'Booking {$response.body#/id} confirmed'

Null Safety #

Check for null values in conditions:

successCriteria:
  # Check for null/undefined
  - condition: $response.body#/email != null
  - condition: $response.body#/address != null
  - condition: $response.body#/id != null

Extracting values #

Use outputs to extract values from responses:

outputs:
  # Extract simple values
  bookingId: $response.body#/id
  customerEmail: $response.body#/customer/email
  tripPrice: $response.body#/trip/price
  
  # Extract nested values
  originCity: $response.body#/trip/origin/city
  destinationCity: $response.body#/trip/destination/city

Examples #

Expressions are frequently used in success and failure criteria. Here’s a comprehensive guide to condition patterns:

Status code checks #

  # Exact status
  - condition: $statusCode == 200
  - condition: $statusCode == 201
  
  # Status ranges
  - condition: $statusCode >= 200 && $statusCode < 300
  
  # Multiple acceptable codes
  - condition: $statusCode == 200 || $statusCode == 201

Field value checks #

# Simple field checks
- condition: $response.body#/status == 'confirmed'
- condition: $response.body#/stock > 0
- condition: $response.body#/payment/processed == true

# Field existence
- condition: $response.body#/id != null
- condition: $response.body#/bookingReference != null

Checking response structure #

# Check for required object properties
- condition: $response.body#/trip != null
- condition: $response.body#/trip/available == true
- condition: $response.body#/trip/price <= $inputs.maxPrice

Header checks #

  # Header values
  - condition: $response.header['content-type'] == 'application/json'
  - condition: $response.header['x-api-version'] == '2024-01'
  
  # Rate limiting (header values are strings)
  - condition: $response.header['x-rate-limit-remaining'] != '0'
  - condition: $response.header['retry-after'] == null

JSONPath in conditions #

For complex filtering, use JSONPath expressions with type: jsonpath. This is only available in conditions (successCriteria/failureCriteria), not in outputs or parameters.


# Check all bookings are confirmed
- type: jsonpath
  context: $response.body
  condition: $.bookings[?(@.status != 'confirmed')][0] == null

# At least one affordable trip
- type: jsonpath
  context: $response.body
  condition: $.trips[?(@.price < 100)][0] != null

# Find child passengers
- type: jsonpath
  context: $response.body
  condition: $.passengers[?(@.age < 18)][0] != null

# No critical errors
- type: jsonpath
  context: $response.body
  condition: $.errors[?(@.severity == 'critical')][0] == null

Mastering runtime expressions enables you to build dynamic, data-driven workflows that respond intelligently to API responses and user inputs.

The Cheat Sheet