Skip to content
LambogeniusDocs

Compose using Liquid for Azure Logic Apps

Parameters and variables

Pass values from app settings, workflow parameters, the trigger and workflow variables, and read typed results back.

Service provider/serviceProviders/lamboLiquidComposeOperation ComposeLiquid, shown in the designer as Compose using Liquid.

Parameters

A template sees content and parameters, nothing else. parameters is an object: pass what the template needs from anywhere in the workflow.

"parameters": {
  "environment": "@appsetting('ENVIRONMENT_NAME')",
  "region":      "@parameters('region')",
  "limits":      "@parameters('limits')",                       // an object: parameters.limits.discountPercent
  "tenant":      "@triggerOutputs()?['headers']?['x-tenant']",
  "mode":        "@triggerOutputs()?['queries']?['mode']",
  "receivedAt":  "@utcNow()"
}

Objects stay objects and arrays stay lists. Don't pass secrets this way: action inputs are kept in the run history.

Workflow variables

Variables of every type map straight onto parameters and keep their type in the template:

Variable typeIn the template
string{{ parameters.currency }}
integer{% for line in content.lines limit: parameters.maxLines %}
floatsubtotal | Times: parameters.taxRate | Round: 2
boolean{% if parameters.expedite %}
arraya list: Join, Size, First, for
objectparameters.shipTo.city
"Initialize_the_quote_settings": {
  "type": "InitializeVariable",
  "inputs": { "variables": [
    { "name": "currency",     "type": "string",  "value": "@{toUpper(coalesce(triggerOutputs()?['queries']?['currency'], 'CAD'))}" },
    { "name": "maxLines",     "type": "integer", "value": "@int(coalesce(triggerOutputs()?['queries']?['maxLines'], '10'))" },
    { "name": "taxRate",      "type": "float",   "value": "@float(coalesce(triggerOutputs()?['queries']?['taxRate'], '0.15'))" },
    { "name": "expedite",     "type": "boolean", "value": "@equals(triggerOutputs()?['headers']?['x-expedite'], 'true')" },
    { "name": "excludedSkus", "type": "array",   "value": "@split(triggerOutputs()?['queries']?['exclude'], ',')" },
    { "name": "shipTo",       "type": "object",  "value": "@triggerBody()?['shipTo']" }
  ] }
},
"Quote_the_order": {
  "type": "ServiceProvider",
  "inputs": {
    "parameters": {
      "inputFormat": "json", "outputFormat": "json", "content": "@triggerBody()",
      "templateSource": "deployed", "templateName": "quote.liquid",
      "parameters": {
        "currency": "@variables('currency')",          // {{ parameters.currency }}
        "maxLines": "@variables('maxLines')",          // {% for line in content.lines limit: parameters.maxLines %}
        "taxRate": "@variables('taxRate')",            // subtotal | Times: parameters.taxRate
        "expedite": "@variables('expedite')",          // {% if parameters.expedite %}
        "excludedSkus": "@variables('excludedSkus')",  // a list
        "shipTo": "@variables('shipTo')"               // parameters.shipTo.city
      }
    },
    …
  }
},
"Set_total": {
  "type": "SetVariable",
  "inputs": { "name": "total", "value": "@body('Quote_the_order')?['result']?['total']" }   // a number, not text
}

Results back into variables

  • Typed values: in JSON mode, result fields are numbers, Booleans, arrays and objects, so Set variable, Increment and Append to array take them directly.
  • Route on an answer: a text template can return one word (auto, review, reject) that a Switch acts on. Trim it with trim() in case of a stray line break.
  • Pick the template at run time: templateName and outputFormat accept expressions, such as @variables('templateName').

Loops

Transform each item of a batch, collect the results in variables, then render the collected array:

"For_each_order": {
  "type": "Foreach",
  "foreach": "@triggerBody()?['orders']",
  "runtimeConfiguration": { "concurrency": { "repetitions": 1 } },
  "actions": {
    "Summarize_the_order": { … "content": "@items('For_each_order')",
                             "parameters": { "position": "@add(variables('orderCount'), 1)" } … },
    "Append_to_summaries": { "type": "AppendToArrayVariable",
      "inputs": { "name": "summaries", "value": "@body('Summarize_the_order')?['result']" } },
    "Increment_batchTotal": { "type": "IncrementVariable",
      "inputs": { "name": "batchTotal", "value": "@body('Summarize_the_order')?['result']?['total']" } }
  }
},
"Write_the_report": { … "content": "@variables('summaries')", "outputFormat": "text" … }

Keep the loop sequential when its iterations change the same variables. Sample 08 runs all of this.