Azure Logic Apps Expressions & Functions
Dynamic Workflow Logic
Introduction
Logic Apps expressions provide a powerful way to create dynamic, data-driven workflows. Expressions allow you to access and transform data, perform calculations, make decisions, and construct complex values at runtime. Understanding expressions is essential for building sophisticated integration workflows that can handle varying data formats and business conditions.
This comprehensive guide covers:
- Expression syntax — Understanding @{} notation
- Function categories — String, date, logical, collection operations
- Data access — Reading from triggers and previous actions
- Variable operations — Working with variables and arrays
- Complex expressions — Building nested, multi-function expressions
- Best practices — Writing efficient, maintainable expressions
Understanding Expression Syntax
Basic Expression Structure
┌─────────────────────────────────────────────────────────────────────┐
│ EXPRESSION SYNTAX │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Simple Expression │
│ ────────────────── │
│ @{triggerBody()['orderId']} │
│ │ │ │
│ │ └── JSON path (orderId) │
│ │ │
│ └──── Expression wrapper (always use @{}) │
│ │
│ Function Expression │
│ ─────────────────── │
│ @{toUpper('hello world')} │
│ │ │ │
│ │ └── Function parameter │
│ │ │
│ └────── Function name (toUpper) │
│ │
│ Nested Expression │
│ ────────────────── │
│ @{addDays(utcNow(), variables('daysToAdd'))} │
│ │ │ │ │ │
│ │ │ │ └── Variable reference │
│ │ │ └──── Parameter │
│ │ └──── Nested function call │
│ └──────── Outer function │
│ │
└─────────────────────────────────────────────────────────────────────┘
Expression Evaluation Flow
┌─────────────────────────────────────────────────────────────────────┐
│ EXPRESSION EVALUATION FLOW │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ DESIGN TIME (Logic App Editor) │ │
│ │ │ │
│ │ "@addDays(utcNow(), 7)" │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ Validated and type-checked │ │
│ └────────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ RUNTIME (Workflow Execution) │ │
│ │ │ │
│ │ 1. Evaluate: utcNow() → 2024-01-15T10:30:00Z │ │
│ │ 2. Evaluate: 7 (constant) → 7 │ │
│ │ 3. Execute: addDays(result1, result2) │ │
│ │ 4. Result: 2024-01-22T10:30:00Z │ │
│ └────────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ OUTPUT (Action Input) │ │
│ │ │ │
│ │ Used as parameter in next action │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
String Functions
Common String Operations
{
"Transform_text": {
"type": "Compose",
"inputs": {
"uppercase": "@toUpper('hello world')",
"lowercase": "@toLower('HELLO WORLD')",
"trimmed": "@trim(' hello world ')",
"substring": "@substring('Hello World', 0, 5)",
"length": "@length('Hello')",
"concat": "@concat('Hello', ' ', 'World')",
"replace": "@replace('Hello World', 'World', 'Universe')",
"split": "@split('a,b,c', ',')",
"startsWith": "@startsWith('Hello World', 'Hello')",
"endsWith": "@endsWith('Hello World', 'World')"
}
}
}
String Function Reference
| Function | Description | Example |
|---|---|---|
toUpper(text) | Convert to uppercase | @toUpper('hello') → "HELLO" |
toLower(text) | Convert to lowercase | @toLower('HELLO') → "hello" |
trim(text) | Remove leading/trailing spaces | @trim(' hello ') → "hello" |
substring(text, start, length) | Extract substring | @substring('Hello', 0, 3) → "Hel" |
length(text) | Get string length | @length('Hello') → 5 |
concat(text1, text2, ...) | Concatenate strings | @concat('A', 'B') → "AB" |
replace(text, old, new) | Replace substring | @replace('Hi', 'Hi', 'Hello') → "Hello" |
split(text, delimiter) | Split into array | @split('a,b', ',') → ["a","b"] |
startsWith(text, prefix) | Check prefix | @startsWith('Hello', 'He') → true |
endsWith(text, suffix) | Check suffix | @endsWith('Hello', 'lo') → true |
JSON String Functions
{
"Json_operations": {
"type": "Compose",
"inputs": {
"parse": "@json('{\"name\": \"John\"}')",
"stringify": "@string(json('{\"name\": \"John\"}'))",
"base64_encode": "@base64('Hello')",
"base64_decode": "@base64ToString('SGVsbG8=')"
}
}
}
Date and Time Functions
DateTime Operations
{
"Date_operations": {
"type": "Compose",
"inputs": {
"current_time": "@utcNow()",
"formatted_date": "@formatDateTime(utcNow(), 'yyyy-MM-dd')",
"formatted_datetime": "@formatDateTime(utcNow(), 'yyyy-MM-ddTHH:mm:ssZ')",
"add_days": "@addDays(utcNow(), 7)",
"add_hours": "@addHours(utcNow(), 2)",
"add_minutes": "@addMinutes(utcNow(), 30)",
"start_of_day": "@startOfDay(utcNow())",
"end_of_day": "@endOfDay(utcNow())",
"start_of_week": "@startOfWeek(utcNow())",
"timestamp_to_ticks": "@ ticks(utcNow())"
}
}
}
Date Format Patterns
┌─────────────────────────────────────────────────────────────────────┐
│ DATE FORMAT PATTERNS │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Pattern Description Example │
│ ──────── ────────────── ──────── │
│ yyyy Year (4 digits) 2024 │
│ MM Month (2 digits) 01 │
│ dd Day (2 digits) 15 │
│ HH Hour (24-hour) 14 │
│ mm Minutes 30 │
│ ss Seconds 45 │
│ fff Milliseconds 123 │
│ zzz Timezone offset +05:30 │
│ │
│ Common Formats │
│ ───────────── │
│ 'yyyy-MM-dd' → "2024-01-15" │
│ 'yyyy-MM-dd HH:mm' → "2024-01-15 14:30" │
│ 'yyyy-MM-ddTHH:mm:ssZ'→ "2024-01-15T14:30:45Z" │
│ 'MMMM dd, yyyy' → "January 15, 2024" │
│ │
└─────────────────────────────────────────────────────────────────────┘
Timezone Conversion
{
"Timezone_operations": {
"type": "Compose",
"inputs": {
"utc_to_pst": "@convertFromUtc(utcNow(), 'Pacific Standard Time')",
"pst_to_utc": "@convertToUtc('2024-01-15 14:30', 'Pacific Standard Time')",
"utc_to_ist": "@convertFromUtc(utcNow(), 'India Standard Time')"
}
}
}
Collection Functions
Array and Object Operations
{
"Collection_operations": {
"type": "Compose",
"inputs": {
"array_length": "@length(createArray(1, 2, 3))",
"first_item": "@first(createArray(1, 2, 3))",
"last_item": "@last(createArray(1, 2, 3))",
"take_items": "@take(createArray(1, 2, 3, 4, 5), 3)",
"skip_items": "@skip(createArray(1, 2, 3, 4, 5), 2)",
"contains": "@contains(createArray(1, 2, 3), 2)",
"union_arrays": "@union(createArray(1, 2), createArray(2, 3))",
"intersection": "@intersection(createArray(1, 2, 3), createArray(2, 3, 4))"
}
}
}
Object Property Access
{
"Object_operations": {
"type": "Compose",
"inputs": {
"object_keys": "@keys(json('{\"a\": 1, \"b\": 2}'))",
"object_values": "@values(json('{\"a\": 1, \"b\": 2}'))",
"coalesce": "@coalesce(null, 'default')",
"coalesce_nested": "@coalesce(body('GetOrder')?['customerName'], variables('defaultName'))"
}
}
}
Filter and Map Arrays
{
"Filter_and_map": {
"type": "Compose",
"inputs": {
"filter_items": "@filter(createArray(1, 2, 3, 4, 5), (item) => greater(item, 2))",
"map_items": "@map(createArray(1, 2, 3), (item) => mul(item, 10))"
}
}
}
Logical Functions
Conditionals and Comparisons
{
"Logical_operations": {
"type": "Compose",
"inputs": {
"if_then_else": "@if(equals(variables('status'), 'active'), 'Active', 'Inactive')",
"equals": "@equals(1, 1)",
"not_equals": "@notEquals(1, 2)",
"greater": "@greater(10, 5)",
"greaterOrEquals": "@greaterOrEquals(10, 10)",
"less": "@less(5, 10)",
"lessOrEquals": "@lessOrEquals(5, 5)",
"and": "@and(equals(1, 1), equals(2, 2))",
"or": "@or(equals(1, 1), equals(2, 3))",
"not": "@not(equals(1, 2))"
}
}
}
Nested Conditions
{
"Nested_condition": {
"type": "Compose",
"inputs": {
"complex_if": "@if(and(greater(variables('amount'), 1000), equals(variables('priority'), 'high')), 'Priority Processing', if(greater(variables('amount'), 500), 'Standard Processing', 'Basic Processing'))"
}
}
}
Access Trigger Data
Trigger Body Access
{
"Access_trigger": {
"type": "Compose",
"inputs": {
"full_body": "@triggerBody()",
"specific_field": "@triggerBody()['orderId']",
"nested_field": "@triggerBody()['customer']['email']",
"array_item": "@triggerBody()['items'][0]",
"array_length": "@length(triggerBody()['items'])"
}
}
}
Trigger Headers and Outputs
{
"Access_outputs": {
"type": "Compose",
"inputs": {
"headers": "@triggerOutputs()['headers']",
"statusCode": "@triggerOutputs()['statusCode']",
"specific_header": "@triggerOutputs()['headers']['Content-Type']",
"reasonPhrase": "@triggerOutputs()['reasonPhrase']"
}
}
}
HTTP Trigger Expressions
{
"Http_trigger_expressions": {
"type": "Compose",
"inputs": {
"query_param": "@trigger().queries.page",
"path_param": "@trigger().parameters.id",
"method": "@trigger().method",
"uri": "@trigger().uri"
}
}
}
Access Action Outputs
Reference Previous Actions
{
"Action_output_access": {
"type": "Compose",
"inputs": {
"parse_result": "@body('Parse_JSON')",
"specific_field": "@body('Parse_JSON')['orderId']",
"action_result": "@outputs('Get_Order')",
"status_code": "@outputs('HTTP_Request')['statusCode']",
"headers": "@outputs('HTTP_Request')['headers']"
}
}
}
Handle Missing Data
{
"Safe_data_access": {
"type": "Compose",
"inputs": {
"coalesce": "@coalesce(body('Get_Order')?['customerName'], 'Unknown')",
"conditional_access": "@if(contains(body('Get_Order'), 'customerName'), body('Get_Order')['customerName'], 'N/A')",
"null_check": "@if(empty(body('Get_Customer')), 'Not Found', body('Get_Customer')['name'])"
}
}
}
Complex Expression Examples
Date Calculation Pipeline
{
"Calculate_dates": {
"type": "Compose",
"inputs": {
"today": "@utcNow()",
"next_week": "@addDays(utcNow(), 7)",
"next_week_formatted": "@formatDateTime(addDays(utcNow(), 7), 'yyyy-MM-dd')",
"start_of_month": "@formatDateTime(startOfMonth(utcNow()), 'yyyy-MM-01')",
"end_of_month": "@formatDateTime(endOfMonth(utcNow()), 'yyyy-MM-dd')",
"relative_date": "@if(greater(dayOfWeek(utcNow()), 4), addDays(utcNow(), 14), addDays(utcNow(), 7))"
}
}
}
Data Transformation Pipeline
{
"Transform_data": {
"type": "Compose",
"inputs": {
"original": {
"firstName": "john",
"lastName": "doe",
"email": "JOHN@EXAMPLE.COM"
},
"transformed": {
"fullName": "@concat(toUpper(body('original')['firstName']), ' ', toUpper(body('original')['lastName']))",
"normalizedEmail": "@toLower(body('original')['email'])",
"initials": "@concat(substring(body('original')['firstName'], 0, 1), substring(body('original')['lastName'], 0, 1))"
}
}
}
}
Array Processing
{
"Process_arrays": {
"type": "Compose",
"inputs": {
"items": [
{ "name": "Item1", "price": 100 },
{ "name": "Item2", "price": 250 },
{ "name": "Item3", "price": 50 }
],
"total_price": "@sum(body('items')[*]['price'])",
"expensive_items": "@filter(body('items'), (item) => greater(item['price'], 100))",
"item_names": "@map(body('items'), (item) => item['name'])"
}
}
}
Use in Different Action Types
Set Variable
{
"Set_variable": {
"type": "SetVariable",
"inputs": {
"name": "orderId",
"value": "@triggerBody()['orderId']"
}
}
}
Condition (If)
{
"If_action": {
"type": "If",
"expression": "@greater(variables('totalAmount'), 1000)",
"actions": {
"Send_priority_email": { "type": "SendEmail" }
},
"else": {
"Send_normal_email": { "type": "SendEmail" }
}
}
}
Switch
{
"Switch_action": {
"type": "Switch",
"expression": "@triggerBody()['status']",
"cases": {
"new": {
"actions": {
"Handle_new": { "type": "HandleNewOrder" }
}
},
"processing": {
"actions": {
"Handle_processing": { "type": "HandleProcessing" }
}
},
"completed": {
"actions": {
"Handle_completed": { "type": "HandleCompleted" }
}
}
}
}
}
For Each Loop
{
"For_each": {
"type": "ForEach",
"foreach": "@body('Get_Orders')['orders']",
"actions": {
"Process_item": {
"type": "Compose",
"inputs": {
"itemName": "@item()['name']",
"upperName": "@toUpper(item()['name'])"
}
}
}
}
}
Best Practices
Expression Design
| Practice | Description |
|---|---|
| Use coalesce | Handle null/missing values safely |
| Test thoroughly | Verify expressions with various inputs |
| Keep simple | Break complex expressions into steps |
| Document intent | Add comments for complex logic |
Performance Considerations
{
"Performance_tips": {
"type": "Compose",
"inputs": {
"good": "@body('Get_Order')['customerId']",
"avoid": "@if(contains(body('Get_Order'), 'customerId'), body('Get_Order')['customerId'], '')"
}
}
}
Debugging Expressions
{
"Debug_compose": {
"type": "Compose",
"inputs": {
"debug_value": "@variables('myVariable')",
"trace": "@concat('Processing order: ', string(variables('orderId')))"
}
}
}
Related Topics
- Error Handling — Try/Catch patterns
- Parallel Execution — Concurrent processing
- Azure Functions — Call functions from Logic Apps
Azure Integration Hub - Intermediate Level