Error in setting variable from JSON request body in APIM

Nitya Singh (INDIA - BAS) 25 Reputation points
2023-05-18T06:15:06.27+00:00

Following is the JSON request body from which i need to read values-

{
"User Id":"123","Name":"Raj","Employee Id":"3425667","Skill Set":"Java Developer"}

Following is the policy code which was working earlier but when i tried today its giving me error-

<policies>
    <inbound>
        <base />
        <set-variable name="mode" value="@(context.Request.OriginalUrl.Query.GetValueOrDefault("mode"))" />
        <choose>
            <when condition="@(context.Variables.GetValueOrDefault<string>("mode") == "dev")">
                <return-response>
                    <set-status code="200" />
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>{  
                        "StatusCode": "200",  
                        "Success Message": "Redirected to backend services."  
                }</set-body>
                </return-response>
            </when>
            <otherwise />
        </choose>
    </inbound>
    <backend />
    <outbound>
        <base />
        <choose>
            <when condition="@(string.IsNullOrEmpty(context.Request.Body.As<JObject>(true)["User Id"].Value<string>()))">
                <return-response>
                    <set-status code="404" />
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>{  
                        "statusCode": "404",  
                        "Error Message" : "Missing User Id of Employee" 
                }</set-body>
                </return-response>
            </when>
        </choose>
        <choose>
            <when condition="@(string.IsNullOrEmpty(context.Request.Body.As<JObject>(true)["Name"].Value<string>()))">
                <return-response>
                    <set-status code="404" />
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>{  
                        "statusCode": "404",  
                        "Error Message" : "Missing Name of Employee" 
                }</set-body>
                </return-response>
            </when>
        </choose>
        <choose>
            <when condition="@(string.IsNullOrEmpty(context.Request.Body.As<JObject>(true)["Employee Id"].Value<string>()))">
                <return-response>
                    <set-status code="404" />
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>{  
                        "statusCode": "404",  
                        "Error Message" : "Missing Employee Id of Employee" 
                }</set-body>
                </return-response>
            </when>
        </choose>
        <choose>
            <when condition="@(string.IsNullOrEmpty(context.Request.Body.As<JObject>(true)["Skill Set"].Value<string>()))">
                <return-response>
                    <set-status code="404" />
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>{  
                        "statusCode": "404",  
                        "Error Message" : "Missing Skill Details of Employee" 
                }</set-body>
                </return-response>
            </when>
            <otherwise>
                <return-response>
                    <set-status code="200" />
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>{  
                        "statusCode": "200",  
                        "Message" : "Details saved successfully" 
                }</set-body>
                </return-response>
            </otherwise>
        </choose>
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Following is the error that i am receiving since yesterday-

choose (0.535 ms)
{
    "messages": [
        {
            "message": "Expression evaluation failed.",
            "expression": "string.IsNullOrEmpty(context.Request.Body.As<JObject>(true)[\"User Id\"].Value<string>())",
            "details": "The message body is not a valid JSON. Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '', line 1, position 103.\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)"
        },
        "Expression evaluation failed. The message body is not a valid JSON. Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '', line 1, position 103.\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)",
        "Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '', line 1, position 103."
    ]
}
Azure API Management
Azure API Management
An Azure service that provides a hybrid, multi-cloud management platform for APIs.
1,930 questions
Azure
Azure
A cloud computing platform and infrastructure for building, deploying and managing applications and services through a worldwide network of Microsoft-managed datacenters.
1,063 questions
0 comments No comments
{count} votes

Accepted answer
  1. MuthuKumaranMurugaachari-MSFT 22,266 Reputation points
    2023-05-18T14:29:14.93+00:00

    Nitya Singh (INDIA - BAS) Thanks for posting your question in Microsoft Q&A. We found that after upgrade, API calls were failing to read the request body as JObject due to a bug. Our engineering team has identified the impacted services and rolled them back for immediate mitigation. Sorry for the inconvenience caused by the issue. If you have any questions or still face the issues, please let us know.


    If you found the answer to your question helpful, please take a moment to mark it as "Yes" for others to benefit from your experience. Or simply add a comment tagging me and would be happy to answer your questions.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. MuthuKumaranMurugaachari-MSFT 22,266 Reputation points
    2023-05-19T14:32:44.9166667+00:00

    Nitya Singh (INDIA - BAS) Checking your APIM instance, the rollback is already completed. However, I observed that you haven’t set preserveContent of the request body as true in the Inbound section. By default, context.Request.Body is not preserved at the outbound pipeline since the request is already sent to the backend (refer https://learn.microsoft.com/en-us/azure/api-management/set-body-policy#usage-notes). If you are looking to access the request body in the Outbound section, then use expression context.Request.Body.As<JObject>(preserveContent: true) anywhere in the inbound section like below (as an example):

    <set-variable name="var" value="@(context.Request.Body.As<JObject>(preserveContent: true))" />
    

    I hope this helps and let me know if you have any questions.

    0 comments No comments