Standard Library

The emulator supports all Google Cloud Workflows standard library functions.

Built-in expression helpers

These functions are called directly in expressions without a module prefix.

FunctionDescriptionExample
default(value, fallback)Returns value if not null, otherwise fallback${default(x, 0)}
keys(map)List of map keys (strings)${keys(my_map)}
len(value)Length of string, list, or map${len(items)}
type(value)Type name as string${type(x)} returns "int", "string", etc.
int(value)Convert to integer${int("42")}, ${int(2.7)} -> 2
double(value)Convert to double${double("3.14")}, ${double(42)}
string(value)Convert to string${string(42)} -> "42"
bool(value)Convert string to boolean${bool("true")} -> true

Notes:

  • default() only handles null. It does not catch KeyError. Combine with map.get() for safe map access: ${default(map.get(m, "key"), "fallback")}.
  • int() from double truncates toward zero: int(-2.7) = -2.
  • string() does not work on maps, lists, or null. Use json.encode_to_string() for those.
  • keys() does not guarantee key order.

http

HTTP client functions. All HTTP call steps make real HTTP requests to the target URL.

Methods

- step:
    call: http.get    # or http.post, http.put, http.patch, http.delete
    args:
      url: http://localhost:9090/api/data
      headers:
        Authorization: "Bearer ${token}"
        Content-Type: "application/json"
      body:
        key: "value"
      query:
        limit: "10"
        offset: "0"
      timeout: 30
    result: response
ArgumentTypeRequiredDescription
urlstringYesTarget URL (HTTP or HTTPS)
headersmapNoRequest headers
bodyanyNoRequest body (auto-serialized to JSON if no Content-Type)
querymapNoURL query parameters (URL-encoded automatically)
authmapNoAuth config (accepted but not enforced by emulator)
timeoutintNoTimeout in seconds (max 1800, default 1800)

http.request

Generic HTTP call with explicit method:

- step:
    call: http.request
    args:
      method: "PUT"
      url: http://localhost:9090/api/resource
      body:
        key: "value"
    result: response

Response structure

response.body     # Parsed body (JSON auto-parsed to map/list; text stays as string)
response.code     # HTTP status code (integer)
response.headers  # Response headers (map, keys are lowercased)

Auto-behaviors

  • Request body: If no Content-Type header is set and body is not bytes, the body is JSON-encoded and Content-Type is set to application/json; charset=utf-8.
  • Response parsing: If the response Content-Type is application/json, the body is automatically parsed from JSON to a map/list. Text content types return a string. Everything else returns bytes.
  • Response headers: Header names are lowercased.
  • Non-2xx responses: Raise an error with tag HttpError containing the status code, response body, and headers.

Error behavior

ScenarioError tag
Target service not running (connection refused)ConnectionFailedError
Connection broke mid-transferConnectionError
Request exceeded timeoutTimeoutError
Non-2xx HTTP responseHttpError

Retry policies

PolicyRetries onDoes NOT retry
http.default_retry429, 502, 503, 504, ConnectionError, TimeoutError500
http.default_retry_non_idempotentSame as above500

Both use retry.default_backoff (initial 1s, max 60s, multiplier 1.25) with max_retries 5.

Important: http.default_retry does not retry HTTP 500 errors. This surprises many users. If you need to retry 500s, write a custom retry predicate.


sys

sys.get_env(name)

Returns the value of an environment variable as a string.

- step:
    assign:
      - project: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}

Built-in variables provided by the emulator:

VariableDescription
GOOGLE_CLOUD_PROJECT_IDProject ID (from PROJECT env var)
GOOGLE_CLOUD_LOCATIONLocation (from LOCATION env var)
GOOGLE_CLOUD_WORKFLOW_IDCurrent workflow ID
GOOGLE_CLOUD_WORKFLOW_REVISION_IDCurrent revision ID
GOOGLE_CLOUD_WORKFLOW_EXECUTION_IDCurrent execution ID

Raises KeyError if the variable name is not found.

sys.log(data, severity)

Logs a message. The emulator prints to stdout.

- step:
    call: sys.log
    args:
      data: "Processing started"
      severity: "INFO"

Also accepts text as an alias for data, and json for structured logging.

Severity values: DEFAULT, DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY.

sys.now()

Returns the current Unix timestamp as a double (seconds since epoch).

- step:
    assign:
      - timestamp: ${sys.now()}

sys.sleep(seconds)

Pauses execution for the specified number of seconds.

- step:
    call: sys.sleep
    args:
      seconds: 5

events

Callback support for event-driven async patterns. See also Callbacks in the REST API reference.

events.create_callback_endpoint(http_callback_method)

Creates a callback endpoint that external services can invoke.

- create:
    call: events.create_callback_endpoint
    args:
      http_callback_method: "POST"   # Optional, default "POST"
    result: callback_details
# callback_details.url contains the full callback URL

Supported methods: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH.

events.await_callback(callback, timeout)

Pauses execution until a callback request is received or timeout elapses.

- wait:
    call: events.await_callback
    args:
      callback: ${callback_details}
      timeout: 3600                    # Optional, default 43200 (12 hours)
    result: callback_data

The returned callback_data contains:

callback_data.http_request.body     # Parsed request body
callback_data.http_request.headers  # Request headers
callback_data.http_request.method   # HTTP method used
callback_data.received_time         # Timestamp
callback_data.type                  # "HTTP"

Raises TimeoutError if timeout elapses before a callback is received.

Callback pattern example

main:
  steps:
    - create_callback:
        call: events.create_callback_endpoint
        args:
          http_callback_method: "POST"
        result: cb
    - log_url:
        call: sys.log
        args:
          data: ${cb.url}
    - wait_for_approval:
        try:
          call: events.await_callback
          args:
            callback: ${cb}
            timeout: 300
          result: approval
        except:
          as: e
          steps:
            - check_timeout:
                switch:
                  - condition: ${"TimeoutError" in e.tags}
                    return: "Timed out waiting for approval"
            - rethrow:
                raise: ${e}
    - done:
        return: ${approval.http_request.body}

text

String manipulation functions. All regex functions use RE2 syntax (not PCRE).

FunctionParametersReturnsDescription
text.find_allsource, substrlist of {index, match}Find all substring occurrences
text.find_all_regexsource, patternlist of {index, match}Find all regex matches
text.match_regexsource, patternboolTest if regex matches
text.replace_allsource, substr, replacementstringReplace all occurrences
text.replace_all_regexsource, pattern, replacementstringReplace regex matches (\0 full match, \1-\9 groups)
text.splitsource, separatorlist of stringsSplit string
text.substringsource, start, endstringSubstring (0-based, start inclusive, end exclusive)
text.to_lowersourcestringLowercase
text.to_uppersourcestringUppercase
text.url_encodesourcestringPercent-encode
text.url_decodesourcestringPercent-decode
text.url_encode_plussourcestringPercent-encode with + for spaces
text.decodedata, charsetstringBytes to string (default UTF-8)
text.encodedata, charsetbytesString to bytes (default UTF-8)

json

FunctionParametersReturnsDescription
json.decodedata (string or bytes)anyParse JSON
json.encodevaluebytesEncode to JSON bytes
json.encode_to_stringvaluestringEncode to JSON string
- step:
    assign:
      - parsed: ${json.decode("{\"key\": \"value\"}")}
      - encoded: ${json.encode_to_string(my_map)}

base64

FunctionParametersReturnsDescription
base64.decodedata (string)bytesDecode base64
base64.encodedata (bytes or string)stringEncode to base64

math

FunctionParametersReturnsDescription
math.absvaluesame typeAbsolute value
math.floorvalue (double)intFloor (largest int <= value)
math.maxa, blarger valueMaximum
math.mina, bsmaller valueMinimum

list

FunctionParametersReturnsDescription
list.concatlist, elementnew listAppend element (does not modify original)
list.prependlist, elementnew listPrepend element (does not modify original)
- step:
    assign:
      - items: ${list.concat(items, "new_item")}
      - items: ${list.prepend(items, "first")}

map

FunctionParametersReturnsDescription
map.getmap, key, default?valueGet value without KeyError. Returns null (or default) if missing
map.deletemap, keynew mapRemove key (does not modify original)
map.mergemap1, map2new mapShallow merge (map2 overrides)
map.merge_nestedmap1, map2new mapDeep merge (recursively merges nested maps)
- step:
    assign:
      - value: ${map.get(config, "timeout", 30)}
      - cleaned: ${map.delete(response, "internal_field")}
      - combined: ${map.merge(defaults, overrides)}

uuid

FunctionParametersReturnsDescription
uuid.generate(none)stringRandom UUID v4 (e.g., "550e8400-e29b-41d4-a716-446655440000")

retry

Built-in retry policies for use with try/retry blocks.

PolicyDescription
retry.alwaysAlways retry (returns true for any error)
retry.neverNever retry (returns false for any error)
retry.default_backoffDefault backoff: initial_delay 1s, max_delay 60s, multiplier 1.25

Custom retry predicates

Define a subworkflow that receives the error map and returns true/false:

main:
  steps:
    - call_with_retry:
        try:
          call: http.get
          args:
            url: http://localhost:9090/api
          result: response
        retry:
          predicate: ${my_retry_predicate}
          max_retries: 5
          backoff:
            initial_delay: 1
            max_delay: 60
            multiplier: 2

my_retry_predicate:
  params: [e]
  steps:
    - check:
        switch:
          - condition: ${"ConnectionFailedError" in e.tags}
            return: true
          - condition: ${"TimeoutError" in e.tags}
            return: true
          - condition: ${("HttpError" in e.tags) and (e.code in [429, 500, 502, 503, 504])}
            return: true
    - no_retry:
        return: false

This predicate retries on connection failures, timeouts, and specific HTTP status codes including 500 (which http.default_retry does not retry).