How to use a variable when returning response in p

2020-05-03 18:16发布

问题:

I'm configuring inbound policies in an instance of Azure API Management.

First, I set a variable:

<set-variable name="var1" value="" />

Then I send a request

<send-request mode="new" response-variable-name="var1" timeout="20" ignore-error="false">

Which returns a JSON. When testing I get the following message in trace tab:

GET request to 'https://my-api.azure-api.net/api/data' has been sent, result stored in 'var1' variable.

I guess the send-request policy works and the result is stored in the variable. Then I want to return a response (still in inbound, I get 500 when trying to do it in outbound):

<return-response response-variable-name="existing response variable">
    <set-status code="200" reason="OK" />
    <set-header name="Content-Type" exists-action="override">
        <value>application/json</value>
    </set-header>
    <set-body>
    {
        "success": true,
        "var1": context.Variables["var1"]
    }
    </set-body>
</return-response>

My problem is it doesn't work... It just renders context.Variables["var1"].

And so does:

  • @context.Variables["var1"]
  • @{ context.Variables.GetValueOrDefault<string>("var1") }
  • @context.Variables.GetValueOrDefault("var1")

All of them are rendered as written, no value is being extracted.

Edit: I also tried adding a placeholder string and then using

<find-and-replace from="Placeholder" to="context.Variables.GetValueOrDefault("var1")" />

And try to place it in inbound and outbound alike. But this policy did not launch.

It's a JSON object that I want to append to the response (small detail: in reality I have this issue with multiple variables).

My question is: how can I add my declared variable to the response?

回答1:

There are two ways you can go about this. You could to use policy expressions for that: https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions. The thing to remember is that they can only be used to construct whole value for policy, not part of it, so:

<set-body>@("{\"success\": true, \"var1\": " + ((IResponse)context.Variables["var1"]).Body.As<string>() + "}"</set-body>

Or with set-body policy you could use liquid template:

<set-variable name="var1body" value="@((IResponse)context.Variables["var1"]).Body.As<string>())" />
<set-body template="liquid">
{
    "success": true,
    "var1": {{context.Variables["var1body"]}}
}
</set-body>


回答2:

I assume you have some sidecar request going on additionally to your main request flow.

This sample adds the response from send-request to the response body of the main request:

<policies>
    <inbound>
        <base />
        <!-- main request -->
        <set-backend-service base-url="https://reqres.in" />
        <rewrite-uri template="/api/users/2" />
        <!-- sidecar request -->
        <send-request mode="new" response-variable-name="var1" timeout="20" ignore-error="true">
            <set-url>https://reqres.in/api/unkown/2</set-url>
            <set-method>GET</set-method>
        </send-request>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
        <set-body template="none">@{
            var body = context.Response.Body.As<JObject>(true);
            body["var1"] = ((IResponse)context.Variables["var1"]).Body.As<JObject>();
            return body.ToString();
        }</set-body>
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>