1

I want to rate lime based on the mailTo attribute from the request body.

Here is the APIM policy

<rate-limit-by-key calls="5" 
    renewal-period="10" 
    counter-key="@(context.Request.Body.As<JObject>()["mailTo"].ToString())" />

Here is the request body

{
  "mailTo": "myemail@gmail.com"
}

This work fine for direct call to backend, but getting below error while calling to APIM

{
    "errors": {
        "": [
            "A non-empty request body is required."
        ]
    },
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-......-3be881755d918044-00"
}`
<rate-limit-by-key calls="5" 
    renewal-period="10" 
    counter-key="@(context.Request.Body.As<JObject>()["mailTo"].ToString())" />
Markus Meyer
  • 3,327
  • 10
  • 22
  • 35
Alpesh
  • 15
  • 4

1 Answers1

0

I guess there's much more logic in the policy.

This simple policy does not produce the mentioned error:

<policies>
    <inbound>
        <base />
        <rate-limit-by-key calls="5" renewal-period="10" counter-key="@(context.Request.Body.As<JObject>()["mailTo"].ToString())" />
        <return-response>
            <set-status code="200" reason="Ok" />
            <set-body>{    
    "message": "It's fine!"           
}</set-body>
        </return-response>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

enter image description here

enter image description here

But I guess that the request body is used at least twice in the policy. Therefore you have to set the parameter preserveContent to true:

context.Request.Body.As<JObject>(true)["mailTo"].ToString()

https://learn.microsoft.com/en-us/azure/api-management/api-management-policy-expressions

To avoid that and have the method operate on a copy of the body stream, set the preserveContent parameter to true

Policy which uses the request twice:

<policies>
    <inbound>
        <base />
        <rate-limit-by-key calls="5" renewal-period="10" counter-key="@(context.Request.Body.As<JObject>(true)["mailTo"].ToString())" />
        <set-variable name="email" value="@(context.Request.Body.As<JObject>(true)["mailTo"]?.ToString().ToLower())" />
        <return-response>
            <set-body template="none">@{
                var jsonResponse = new JObject(); 
                jsonResponse.Add(new JProperty("message", (string)context.Variables["email"])); 
                return jsonResponse.ToString(); 
            }</set-body>
        </return-response>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>
Markus Meyer
  • 3,327
  • 10
  • 22
  • 35