Search code examples
azureliquidazure-api-managementdotliquidliquid-template

Why would a previously stable and working Liquid template fail after the most recent Azure API Management upgrade?


We have an Azure API Management endpoint that receives requests in the following format:

{
    "messageType": "EVENT",
    "eventData": {
        "installedApp": {
            "installedAppId": "xxx",
            "locationId": "yyy"
        },
        "events": [
            {
                "eventTime": "2020-11-13T13:14:50.8011105+00:00",
                "eventType": "DEVICE_EVENT",
                "deviceEvent": {
                    "eventId": "3a08b3f3-25b1-11eb-962f-975d499d1166",
                    "locationId": "yyy",
                    "ownerId": "a975533a-a1ae-49f7-88f1-94368bd4d605",
                    "ownerType": "LOCATION",
                    "deviceId": "c3fdc7c6-08f2-4ba3-92b3-0cdfa2b141f5",
                    "componentId": "main",
                    "capability": "motionSensor",
                    "attribute": "motion",
                    "value": "inactive",
                    "valueType": "string",
                    "stateChange": true,
                    "data": {},
                    "subscriptionName": "all_motion_sub"
                }
            }
        ]
    }
}

It passes them through a Liquid template:

<set-body template="liquid">{
    "id": "{{context.Variables["RequestId"]}}",
    "API": "SmartThings",
    "InstalledAppId": "{{body.eventData.installedApp.installedAppId}}",
    "LocationId": "{{body.eventData.installedApp.locationId}}",
    "DeviceEvents":[
        {% assign device_events = body.eventData.events | Where: "eventType", "DEVICE_EVENT" %}
        {% JSONArrayFor event in device_events %}
        {
            "EventId": "{{event.deviceEvent.eventId}}",
            "LocationId": "{{event.deviceEvent.locationId}}",
            "DeviceId": "{{event.deviceEvent.deviceId}}",
            "ComponentId": "{{event.deviceEvent.componentId}}",
            "Capability": "{{event.deviceEvent.capability}}",
            "Attribute": "{{event.deviceEvent.attribute}}",
            "Value": "{{event.deviceEvent.value}}",
            "StateChange": {{event.deviceEvent.stateChange}},
            "EventTime": "{{event.eventTime | Date: "yyyy-MM-ddTHH:mm:sszzz" | Default: context.Variables["RequestDateTime"] }}"
        }
        {% endJSONArrayFor  %}
    ],
    "EventTime": "{{context.Variables["RequestDateTime"]}}"
}</set-body>

And generates an output which is sent to a Logic App for further processing:

{
    "id": "d5e2a032-14b3-40ca-9c6b-4e13f8d2285c",
    "API": "SmartThings",
    "InstalledAppId": "xxx",
    "LocationId": "yyy",
    "DeviceEvents": [
        {
            "EventId": "3a08b3f3-25b1-11eb-962f-975d499d1166",
            "LocationId": "yyy",
            "DeviceId": "c3fdc7c6-08f2-4ba3-92b3-0cdfa2b141f5",
            "ComponentId": "main",
            "Capability": "motionSensor",
            "Attribute": "motion",
            "Value": "inactive",
            "StateChange": true,
            "EventTime": "2020-11-13T13:14:50.8011105+00:00"
        }
    ],
    "EventTime": "2020-11-13T13:14:50.8011105+00:00"
}

Until around 23:00Z on 11/11/2020, this worked as expected, and had been working in production for several months. Commencing at that time, the Liquid mapping began to fail, producing instead:

{
    "id": "2c93647c-f9ef-4747-adfb-985805a71f0c",
    "API": "SmartThings",
    "InstalledAppId": "xxx",
    "LocationId": "yyy",
    "DeviceEvents": [
        {
            "EventId": "",
            "LocationId": "",
            "DeviceId": "",
            "ComponentId": "",
            "Capability": "",
            "Attribute": "",
            "Value": "",
            "StateChange": ,
            "EventTime": "2020-11-13T13:14:50.8011105+00:00"
        }
    ],
    "EventTime": "2020-11-13T13:14:50.8011105+00:00"
}

We have a scheduled maintenance event in the logs to 'Upgrade API Management' from midnight Thursday, so it looks like there was some kind of breaking change.

What changed to cause this, and how do we go about fixing it?


Solution

  • For this problem, I test it in my side and also reproduce your situation. It seems there is bug of liquid template in APIM. After reproduce your problem, I test in another APIM but it doesn't show same problem, the liquid template works fine in that APIM. Then I test in multiple APIM(with same set-body policy and request body) and summarize the result as below:

    enter image description here

    According to many test and the test result above, I guess it may be some bug after upgrade APIM. And the bug may be related to location or pricing tier(I'm not sure) because I can't find any differences between these APIM except location and pricing tier. So I suggest you to do same job in another APIM(with different location and pricing tier), it will solve the problem temporarily.

    ===============================Update=============================

    I did some further test and found a workaround for this problem. I found the problem was caused by the line {% assign device_events = body.eventData.events | Where: "eventType", "DEVICE_EVENT" %}. If we don't assign body.eventData.events to device_events, instead use body.eventData.events directly in for loop like {% JSONArrayFor event in body.eventData.events %}. Then the liquid template works fine.

    So we can just remove the line of "assign" and do "where" condition in for loop. Please refer to my liquid template below: enter image description here