APIM – handling a JSON array response from a send-request policy

Posted: April 29, 2020  |  Categories: Azure

In this blog I show an example of a APIM send-request policy , subsequently using the response, a JSON array, in another call to the backend service. I highlight a special problem I had retrieving a value from the JSON array and how I overcame it.

Incidentally the API aggregation solution is a tactical solution until a purpose built API can be created in MYSite.

The APIM Send -request policy

I show a simple version of the policy .

The rest this blog will talk about the line where we retrieve a JSON value for ItemCode namely

@((string)((IResponse)context.Variables[“code”]).Body.As<JObject>()[0][“ItemCode”])” />

The Issue

On running the policy I get an error like

"messages": [
    {
        "message": "Expression evaluation failed.",
        "expression": "(string)((IResponse)context.Variables[\"code\"]).Body.As<JObject>()[0][\"ItemCode\"]",
        "details": "The message body is not a valid JSON. Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.\r\n   at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings)\r\n   at Microsoft.WindowsAzure.ApiManagement.Proxy.Gateway.MessageBody.AsJObject(Stream stream, Encoding encoding, JsonSerializerSettings settings)\r\n   at Microsoft.WindowsAzure.ApiManagement.Proxy.Gateway.MessageBody.As[T](Boolean preserveContent)"
    },
    "Expression evaluation failed. The message body is not a valid JSON. Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.\r\n   at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings)\r\n   at Microsoft.WindowsAzure.ApiManagement.Proxy.Gateway.MessageBody.AsJObject(Stream stream, Encoding encoding, JsonSerializerSettings settings)\r\n   at Microsoft.WindowsAzure.ApiManagement.Proxy.Gateway.MessageBody.As[T](Boolean preserveContent)",
    "Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1."
] }

The JSON that is returned is a headless array shown below

[    {        “ItemCode”: 5573,        “ProductCode”: “5573”    }]

This is valid JSON but APIM does not like it because it expects non-blank path like

{“Codes”: [    {        “ItemCode”: 5573,        “ProductCode”: “5573”    }] }

A solution

I can’t change the APIM implemenation of JObject but I can workaround it. Firstly I cast the IResponse to a string instead of a JObject. Secondly I prepend the string with {“Codes”: and postpend with a }. Now the array has a head. Thirdly parse the string as a JObject. Finally retrieve the ItemCode value. thus the final solution contains this fragment.

<set-variable name="codes" value="@("{\"Codes\":" + (string((IResponse)context.Variables["code"]).Body.As<string>() + "}")" />

<set-variable name="itemcode" value="@{JObject codes = JObject.Parse((string)context.Variables["codes"]);
return (string)codes["Codes"][0]["ItemCode"];
}" />
<set-backend-service base-url="{{site-BaseUrl-AU}}" />

<base />

 <rewrite-uri template="@("/api/s_v1/Image/GetImage/" + ((string)context.Variables["itemcode"]) + "/")" />
#1 Azure Monitoring Platform

Conclusion

While the JObject implementation in APIM does not support a “headless” JSON array it can be worked around using an APIM expression.

Explore more on Secure Azure Functions Using API Management

turbo360

Back to Top