azureazure-api-managementapimpolicies

Unable to set body & return response in APIM policies, getting 500 error


I am using this code for azure APIM policies

<set-variable name="newRequest" value="@(context.Request.Body?.As<JObject>(preserveContent: true))" />
<set-variable name="insured-id" value="@(context.Request.MatchedParameters["id"].Last())" />
<send-request mode="new" timeout="20" response-variable-name="id" ignore-error="false">
    <set-url>@($"https://api.dev.com/external/workRequest/get")</set-url>
    <set-method>POST</set-method>
    <set-header name="Content-Type" exists-action="override">
        <value>application/json</value>
    </set-header>
    <set-header name="Authorization" exists-action="override">
    <value>@(context.Request.Headers.GetValueOrDefault("Authorization","scheme param"))</value>
    </set-header>
    <set-body>{"insuredId": @($"{(string)context.Variables["insured-id"]}")}</set-body>
</send-request>
<choose>
    <when condition="@((int)((IResponse)context.Variables["id"]).Body.As<JObject>(preserveContent: true)["workRequests"]["entityStatus"]== 1)">
        <return-response response-variable-name="id">
            <set-status code="400" reason="VOID" />
            <set-header name="Content-Type" exists-action="override">
                <value>application/json</value></set-header>
            <set-body>{"statusCode": 400,
                        "message": "The insured cannot be voided as it is currently attached with one or more active workrequest"}</set-body>
            </return-response>
    </when>
    <otherwise />
</choose>

I am taking an insuredId from template parameter of the API operation where I am implementing the APIM policies & using it in the set-body, this will list all the workrequests for that insuredId.

The payload for the POST is something like

{"insuredId": template-parameter}

When returning a response getting 500 error. How to resolve this. The condition which is there is okay. I am suspecting error in set body.

Also how to check whether a particular string like "entityStatus": 1 is there in the response of api, because this https://api.dev.com/external/workRequest/get url will give a list of workrequest records in array form


Solution

  • The request to https://api.dev.com/external/workRequest/get is failing:

    "message": "POST request to 'https://api.dev.com/external/workRequest/get' has been sent, result stored in 'id' variable.",
    "statusCode": "MethodNotAllowed",
    "statusReason": "Method Not Allowed",

    The response of failed request is stored in the variable id. But this response not return any json document in the body.

    Therefore, the following expression is failing and an error 500 is returned:

    "(int)((IResponse)context.Variables[\"id\"]).Body.As<JObject>(preserveContent: true)[\"workRequests\"][\"entityStatus\"]== 1",

    The message body is not a valid JSON. Unexpected character encountered while parsing value: <. Path '', line 0, position 0.\r\n at Newtonsoft.Json.JsonTextReader.ParseValue()\r\n at Microsoft.WindowsAzure.ApiManagement.Proxy.Runtime.Configuration.Models.SyncOnlyDepthTrackingJsonTextReader.Read()\r\n at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings)\r\n at Gateway.Pipeline.IO.JObjectFormatter.Format(JsonTextReader jsonTextReader)\r\n at Gateway.Pipeline.IO.JsonConverter.Convert[T](Stream stream, Encoding encoding, ILog log, Object conversionSettings)\r\n at Microsoft.WindowsAzure.ApiManagement.Proxy.Gateway.MessageBody.As[T](Boolean preserveContent)

    Please check the supported http-methods of https://api.dev.com/external/workRequest/get.
    Maybe your code has to changed to GET:

    <send-request mode="new" timeout="20" response-variable-name="id" ignore-error="false">
    <set-url>@($"https://api.dev.com/external/workRequest/get")</set-url>
    <set-method>GET</set-method>
    

    Trace of request:
    enter image description here


    UPDATE for question from comments:

    thanks, I resolved the issue. The when condition I was using was syntactically wrong as I had a response in the form of array list { "workRequests": [{ "id": 154, "workRequestNumber": "W000154", "insured": {"id": 268,"uri": null, "entityStatus": 1,"workRequestStatus": 0,"entityStatus": 1 },....

    It's better to create a new Stackoverflow Question instead of doing it in comments. Maybe that's what you asking for:

    Request body:

    {
      "workRequests": [
        {
          "id": 154,
          "workRequestNumber": "W000154",
          "insured": {
            "id": 268,
            "uri": null,
            "entityStatus": 1,
            "workRequestStatus": 0
          }
        },
        {
          "id": 154,
          "workRequestNumber": "W000154",
          "insured": {
            "id": 268,
            "uri": null,
            "entityStatus": 0,
            "workRequestStatus": 0
          }
        }
      ]
    }
    

    Response:

    enter image description here

    A variable is assigned with a true value of any entityStatus equals 1.
    The choose policy returns a 400 with entityStatus equals true .

    Policy:

    <inbound>
        <base />
        <set-variable name="isEntityStatusEqualsOne" value="@{
            var body = (JObject)context.Request.Body.As<JObject>(true);
            JArray workrequests = body["workRequests"] as JArray; 
            for(int i = 0; i < workrequests.Count; i++)
            {
                JObject workrequest = workrequests[i] as JObject;
                var entityStatus = ((JValue)workrequest["insured"]["entityStatus"]).Value<int>();
                if(entityStatus == 1)
                {
                    return true;
                }
            }
    
            return false;
        }" />
        <choose>
            <when condition="@(context.Variables.GetValueOrDefault<bool>("isEntityStatusEqualsOne") == true)">
                <return-response response-variable-name="id">
                    <set-status code="400" reason="VOID" />
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>{"statusCode": 400,
                                "message": "The insured cannot be voided as it is currently attached with one or more active workrequest"}</set-body>
                </return-response>
            </when>
            <otherwise>
                <return-response response-variable-name="id">
                    <set-status code="200" reason="OK" />
                </return-response>
            </otherwise>
        </choose>
    </inbound>