1

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

Markus Meyer
  • 3,327
  • 10
  • 22
  • 35
Shree
  • 59
  • 6

2 Answers2

0

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>
Markus Meyer
  • 3,327
  • 10
  • 22
  • 35
  • I checked the logs of the URL `https://api.dev.com/external/workRequest/get` in app insights it has 200 response code for POST method, when the policy implemented – Shree Feb 15 '23 at 06:42
  • Can you share your trace log? At which point does an error occur? – Markus Meyer Feb 15 '23 at 07:04
  • 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 },....` – Shree Feb 15 '23 at 07:25
  • Can you suggest me how to parse through JArray, as I have to do this condition check for entityStatus==1 to all the array elements in that response otherwise is there any option that I can check if "entityStatus": 1 string is present or not in response – Shree Feb 15 '23 at 07:30
  • @Shree I added code for iteration to the existing answer – Markus Meyer Feb 15 '23 at 08:00
0

Try below code, for me it's fine and sending 500 when response code is not 200. I am able to set-body with 500 status code.

   <send-request mode="new" response-variable-name="createBookingResponse">
            <set-url>@(context.Variables.GetValueOrDefault<string>("domainUrl") + $"/api/Booking")</set-url>
            <set-method>POST</set-method>
            <set-header name="Content-Type" exists-action="override">
                <value>application/json</value>
            <set-body>@(context.Variables.GetValueOrDefault<string>("requestPayload"))</set-body>
        </send-request>
        <choose>
            <when condition="@(((IResponse)context.Variables["createBookingResponse"]).StatusCode == 200)">
                <return-response>
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>@(((IResponse)context.Variables["createBookingResponse"]).Body.As<JObject>(preserveContent: true).ToString())</set-body>
                </return-response>
            </when>
            <!-- Return status code if non-200 status from OPA -->
            <otherwise>
                <return-response>
                    <set-status code="500" reason="Internal Server Error" />
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>@(((IResponse)context.Variables["createBookingResponse"]).Body.As<JObject>(preserveContent: true).ToString())</set-body>
                </return-response>
            </otherwise>
        </choose>
Singh Aswal
  • 379
  • 2
  • 6