Search code examples
azure-api-managementazure-policy

Why does Set-Body policy not recognize my POST body?


I'm trying to connect an API endpoint in Azure (api management) to a backend service. However, the set-body policy isn't recognizing my JSON body and thus isn't transforming it for the backend call.

I've tried all iterations i can think of for the "Liquid" and "None" templates. The microsoft documentation is useless as even the "liquid" template is capitalized in the doc while it NEEDS to be lowercase. Even the Deep Dive article that everyone points to is misleading and/or out of date.

i was once able to get the {{context.Request.OriginalUrl}} reference to work using liquid template, but i can't seem to get the {{body.json}} reference to work

Here's the policy i have in the section (purely to test - this has no use for what i'm doing):

<set-body template="liquid">
    Calling User Agent: {{context.Request.OriginalUrl}}
</set-body>

And here's an example of what i have to try to read the json body (passing through via POST):

<set-body template="liquid">{{body}}</set-body>

I've tried several iterations and inputs like below:

<set-body template="liquid">{{body.json}}</set-body>

while passing through a body like this:

{"json":"this is an example body"}

No matter what I do, this is what I see in the trace after testing the call:

set-body (0.069 ms)
{
    "input": null,
    "output": ""
} 

i'm obviously open to using the "none" template, but i run into the same problems. The documentation is wrong - if i copy/paste the example:

<set-body>@(context.Body.As<String>())</set-body>

I get errors like:

One or more fields contain incorrect values:
Error in element 'set-body' on line 32, column 10: 'IProxyRequestContext' does not contain a definition for 'Body' and no extension method 'Body' accepting a first argument of type 'IProxyRequestContext' could be found (are you missing a using directive or an assembly reference?)

and when i do get it to not error, it returns the same "output":"" output.


Solution

  • For being able to access the body as an object in the liquid template, you will have to set the Content-Type header to application/json as mentioned in the docs.
    If your requests are already sending this header, then it should work without setting it too.

    A policy like this in the inbound section will guarantee it works as expected

    <set-header name="Content-Type" exists-action="override">
        <value>application/json</value>
    </set-header>
    <set-body template="liquid">{{body.json}}"}</set-body>
    

    As for accessing it via the context variable, you have to access it as context.Request.Body.As<string>() as mentioned in the docs, so something like this

    <set-body>@(context.Request.Body.As<string>())</set-body>
    

    The official reference for set-body doesn't seem to have the problems you've mentioned.
    Was there any other doc you are referring to? If its on learn.microsoft.com, you could open an issue at the end of each doc.