Expressions & Conditions Guide

This guide walks through common workflow patterns that use expressions and conditions. Each recipe shows the workflow structure, the expression to use, and what the result looks like at runtime.

For the full list of available helpers, see the Expression Reference.


Recipe 1: Check if a Query Parameter Exists

Workflow: API Trigger (GET) → If → Return (200) / Return (400)

Use case: You expose a GET endpoint and want to check whether the caller passed an id query parameter.

Setup

  1. Add an API Trigger node configured for GET
  2. Connect it to an If node
  3. Wire the true output to a Return node (success response)
  4. Wire the false output to another Return node (error response)

If condition

input.query.id

That's it. If id is present in the query string, input.query.id returns the value (truthy). If id is missing, it returns None (falsy), and execution takes the false branch.

Return node (true branch)

Set the body to:

{"{{ {\"status\": \"ok\", \"id\": input.query.id} }}"} 

Return node (false branch)

Set the status to 400 and the body to:

{"{{ {\"error\": \"Missing required parameter: id\"} }}"}

Dot notation on dictionaries is safe — if a key doesn't exist, it returns None instead of throwing an error. This is a Tensorify feature, not standard Python behavior.


Recipe 2: Route by Event Type

Workflow: Webhook Trigger → Switch → different handlers

Use case: A single webhook endpoint receives events from an external service (e.g., Stripe or GitHub), and you want to route to different actions based on the event type.

Setup

  1. Add a Webhook Trigger node
  2. Connect it to a Switch node
  3. Wire each case output to the appropriate handler

Switch condition

input.body.type

Or if the event type is nested:

input.body.event.action

Cases

| Case Label | Match Value | Handler | |------------|------------|---------| | payment_success | payment_intent.succeeded | Send confirmation email | | payment_failed | payment_intent.payment_failed | Send alert | | default | (fallback) | Log and stop |

The Switch node compares the expression result against each case label. The first match wins, or the default branch runs if nothing matches.


Recipe 3: Type-Safe Comparison with eq()

Workflow: Webhook → If → Transform / Stop

Use case: A webhook sends a status field that might be a number (200) or a string ("200"). You need to compare it reliably.

The problem

Python's == is strictly typed:

"200" == 200    # False — different types!

This can cause unexpected behavior when webhook payloads inconsistently send numbers vs strings.

The fix — use eq()

If condition:

eq(input.body.status, 200)

eq() tries numeric coercion first, then string comparison. It returns True for both "200" and 200.

Other examples

eq(input.body.count, 0)           # True for "0" or 0
eq(input.body.price, 9.99)        # True for "9.99" or 9.99
neq(input.body.status, 200)       # True if status is NOT 200

When to use eq() vs ==: Use == when you control both sides (e.g., comparing two strings). Use eq() when data comes from webhooks, APIs, or forms where types are unpredictable.


Recipe 4: Transform Webhook Data

Workflow: Webhook → Transform → HTTP Request

Use case: You receive a webhook from one service and need to reshape the data before sending it to another API.

Transform template (Object mode)

In the Transform node, use {"{{ }}"} expressions to build a new JSON object:

{
  "name": "{"{{ input.body.user.first_name }}"} {"{{ input.body.user.last_name }}"}",
  "email": "{"{{ input.body.user.email }}"}",
  "source": "webhook",
  "received_at": "{"{{ now() }}"}",
  "tags": "{"{{ input.body.metadata.tags }}"}"
}

Transform template (Expression mode)

Or use a single expression to build the entire object:

{"{{ pick(input.body, \"email\", \"name\", \"company\") }}"}

HTTP Request body

Reference the transform output in the next node:

{"{{ transform }}"}

Or cherry-pick fields:

{"{{ to_json(transform) }}"}

Recipe 5: Conditional Data Extraction

Workflow: API Trigger → If → Transform (with dynamic template) → Return

Use case: An API endpoint returns different response shapes depending on whether a detailed query param is passed.

If condition

input.query.detailed

Transform (true branch — detailed response)

{
  "id": "{"{{ input.body.id }}"}",
  "name": "{"{{ input.body.name }}"}",
  "email": "{"{{ input.body.email }}"}",
  "created_at": "{"{{ format_date(input.body.created_at, \"%B %d, %Y\") }}"}",
  "order_count": "{"{{ length(input.body.orders) }}"}",
  "total_spent": "{"{{ sum(pluck(input.body.orders, \"amount\")) }}"}"
}

Transform (false branch — summary response)

{
  "id": "{"{{ input.body.id }}"}",
  "name": "{"{{ input.body.name }}"}"
}

Recipe 6: Multiple Conditions with and / or

Workflow: Webhook → If → different paths

Check multiple fields

input.body.email and input.body.name and input.body.age >= 18

This evaluates to True only if email is present AND name is present AND age is at least 18.

Either/or conditions

input.body.role == "admin" or input.body.role == "owner"

Negation

not is_empty(input.body.tags)

Recipe 7: Working with Lists

Count items

If condition — check if list has items:

length(input.body.items) > 0

Extract field from each item

Transform template:

{"{{ pluck(input.body.users, \"email\") }}"}

Result: ["[email protected]", "[email protected]", ...]

Filter items

Transform template:

{"{{ [item for item in input.body.orders if item.status == \"completed\"] }}"}

Aggregate

Transform template:

{"{{ sum(pluck(input.body.line_items, \"amount\")) }}"}

Recipe 8: Safe Defaults for Missing Data

Using coalesce() — first non-None value

{"{{ coalesce(input.body.display_name, input.body.username, \"Anonymous\") }}"}

Using .get() — dict access with default

{"{{ input.body.get(\"timeout\", 30) }}"}

Using safe_get() — deep nested access

{"{{ safe_get(input, \"body.user.preferences.theme\", \"dark\") }}"}

Using ternary — conditional value

{"{{ input.body.name if input.body.name else \"Unknown\" }}"}

Tips

  • If/Switch conditions are bare expressions — don't wrap them in {"{{ }}"}. Just type input.body.status == 200.
  • Template fields use {"{{ }}"} — URLs, HTTP bodies, email subjects, Transform object fields.
  • Dot notation is safe — accessing a missing key returns None, not an error.
  • Use eq() for webhook data — query params and form values often arrive as strings even when they look like numbers.
  • Chain helpersunique(pluck(input.body.orders, "category")) gives you deduplicated categories.

See Also

On this page