Search code examples
azureazure-api-managementpolicy

Azure API management policy: Unable to check if a parameter exists or not in request body


I am having a control flow where I am specifying policy that will check if location property exists in request body, if exists I am sending the request with<send-request> here is my code:

<set-variable name="location-id" value="@((string)context.Request.Body.As<JObject>(preserveContent: true)["location"]["id"])" />                                                
<choose>
    <when condition="@(!string.IsNullOrEmpty(context.Request.Body.As<JObject>(true)["location"].Value<string>()))">     
        <send-request mode="new" timeout="20" response-variable-name="locationid" ignore-error="false">
            <set-url>@($"https://api.dev.com/external/location/location/{(string)context.Variables["location-id"]}")</set-url>
            <set-method>GET</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>@{ var document = (JObject)context.Variables["newRequest"];
                            return document?.ToString();
                        }</set-body>
        </send-request>
    </when>
    <otherwise />
</choose>

Here is my request body:

{
  "id": 0,
  "policyList": [
    {
      "id": 4,
      "number": "string",
      "uri": "string"
    }
  ],
  "primaryPolicy": {
    "id": 23,
    "number": "string",
    "uri": "string"
  },
  "isLocationAmountRequired": true,
  "currency": 0,

  "location": {
    "id": 1,
    "number": "string",
    "postcode": "string",
    "name": "string",
    "uri": "string"
  },
  "modifiedOn": "string",
  "modifiedBy": {
    "adObjectId": "string",
    "adUserPrincipalName": "string",
    "adName": "string",
    "email": "string"
  }
}

But after doing this I should get a response but I am getting 500 internal server error

{
    "statusCode": 500,
    "message": "Internal server error",
    "activityId": "fa17a054-fbfb-477e-9637-276257808c65"
}

what should I do to solve this issue


Solution

  • Trace is returning following failure:

    choose (10.095 ms)

    {
        "messages": [
            {
                "message": "Expression evaluation failed.",
                "expression": "!string.IsNullOrEmpty(context.Request.Body.As<JObject>(true)[\"location\"].Value<string>())",
                "details": "Cannot cast Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JToken.\r\n   at Newtonsoft.Json.Linq.Extensions.Convert[T,U](T token)"
            },
            "Expression evaluation failed. Cannot cast Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JToken.\r\n   at Newtonsoft.Json.Linq.Extensions.Convert[T,U](T token)",
            "Cannot cast Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JToken."
        ]
    }
    
    1. If the location property is missing, the set-variable will fail before the choose condition. Please move this part into the choose condition:
      <set-variable name="location-id" value="@((string)context.Request.Body.As<JObject>(preserveContent: true)["location"]["id"])" />
    2. Check your request for
      2.1 location is missing: context.Request.Body.As<JObject>(true)["location"] != null
      2.2 location is null: context.Request.Body.As<JObject>(true)["location"].Type != JTokenType.Null
      2.3 Complete when statement: <when condition="@(context.Request.Body.As<JObject>(true)["location"] != null && context.Request.Body.As<JObject>(true)["location"].Type != JTokenType.Null)">

    3.In the end, the missing variable newRequest has to to be added in the policy:

    set-body (0.589 ms)

    {
        "messages": [
            {
                "message": "Expression evaluation failed.",
                "expression": " var document = (JObject)context.Variables[\"newRequest\"];\n                                return document?.ToString();\n                                ",
                "details": "The given key was not present in the dictionary.\r\n   at System.ThrowHelper.ThrowKeyNotFoundException()\r\n   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)"
            },
            "Expression evaluation failed. The given key was not present in the dictionary.\r\n   at System.ThrowHelper.ThrowKeyNotFoundException()\r\n   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)",
            "The given key was not present in the dictionary."
        ]
    }
    

    Complete policy:

    <policies>
        <inbound>
            <base />
            <choose>
                <when condition="@(context.Request.Body.As<JObject>(true)["location"] != null && context.Request.Body.As<JObject>(true)["location"].Type != JTokenType.Null)">
                    <set-variable name="location-id" value="@((string)context.Request.Body.As<JObject>(preserveContent: true)["location"]["id"])" />
                    <send-request mode="new" timeout="20" response-variable-name="locationid" ignore-error="false">
                        <set-url>@($"https://api.dev.com/external/location/location/{(string)context.Variables["location-id"]}")</set-url>
                        <set-method>GET</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>
                        <!-- newRequest is not defined in policy which will cause an error -->
                        <set-body>@{ var document = (JObject)context.Variables["newRequest"];
                                    return document?.ToString();
                                    }</set-body>
                    </send-request>
                </when>
                <otherwise />
            </choose>
        </inbound>
        <backend>
            <base />
        </backend>
        <outbound>
            <base />
        </outbound>
        <on-error>
            <base />
        </on-error>
    </policies>