API Management - Hands-on Lab Script - part 4

Policy Expressions

Policy Expressions are used to control traffic to and modify the behavior of the Backend API. Using C# statements and an ability to access the API context, as well as your API Management service configuration, Policy Expressions are a powerful way to modify the behavior of the API at runtime.

Don’t hesitate to read the documentation

We had a brief look earlier at setting CORS policies. Lets dive in a bit deeper.

Policies can be applied at multiple scopes and follow this hierarchy:

All API - Policies examples

Cross-origin resource sharing (CORS)

The cors policy adds cross-origin resource sharing (CORS) support to an operation or an API to allow cross-domain calls from browser-based clients.

https://docs.microsoft.com/en-us/azure/api-management/api-management-cross-domain-policies#CORS

If you go to the global scope located in ´All APIs´you should find something like this:

<!-- Inbound -->
    <cors allow-credentials="true">
            <allowed-origins>
                <origin>https://famc-apim.developer.azure-api.net</origin>
                <origin>https://markcolorweb.azurewebsites.net</origin>
            </allowed-origins>
            <allowed-methods preflight-result-max-age="300">
                <method>*</method>
            </allowed-methods>
            <allowed-headers>
                <header>*</header>
            </allowed-headers>
            <expose-headers>
                <header>*</header>
            </expose-headers>
        </cors>

Color API - Policies examples

Getting Started - Frontend/Inbound/Outbound/Backend

Select an API e.g. Color API

Edit the Frontend …

Caching

API Management can be configured for response caching - this can significantly reduce API latency, bandwidth consumption, and web service load for data that does not change frequently.

Using the Azure Management portal - set a caching Policy on the RandomColor API call

Look at RandomColor API, switch to ‘Code View’ and check the caching policies (set from earlier)

<!-- Inbound -->
<cache-lookup vary-by-developer="false"
              vary-by-developer-groups="false"
              downstream-caching-type="none" />

<!-- Outbound -->
<cache-store duration="15" />

Transformation - replace string

The find-and-replace policy finds a request or response substring and replaces it with a different substring.

<find-and-replace from="blue" to="yellow" />

With Starter key and Unlimited key:

Star Wars API - Policies examples

Transformation - conditional

Another C# example to manipulate the response body, depending on the product - with this expression a subscriber of the Starter product will only get back a subset of the information. Other products will get the full information.

Not the inbound header is set to ensure that the Response Body is not encoded as that causes the JSON parsing to fail.

<!-- Inbound -->
        <set-header name="Accept-Encoding" exists-action="override">
            <value>deflate</value>
        </set-header>
<!-- Outbound -->
<choose>
    <when condition="@(context.Response.StatusCode == 200 && context.Product.Name.Equals("Starter"))">
        <set-body>@{
                var response = context.Response.Body.As<JObject>();
                foreach (var key in new [] {"hair_color", "skin_color", "eye_color", "gender"}) {
                    response.Property(key).Remove();
                }
                return response.ToString();
            }
        </set-body>
    </when>
</choose>

With Starter key:

With Unlimited key:

Mock responses

Mocking provides a way to return sample responses even when the backend is not available. This enables app developers to not be help up if the backend is under development.

{
  "count": 1,
  "films": [   { "title": "A New Hope",  "blah": "xxx"    }   ]
}

Calculator API - Policies examples

Transformation - XML to JSON

A frequent requirement is to transform content, especially with legacy APIs

Remember the Calc API that returned XML

<!-- Outbound -->
<xml-to-json kind="direct" apply="always" consider-accept-header="false" />

Named Values collection

Named Values (aka Properties) are a collection of key/value pairs that are global to the service instance. These properties can be used to manage constant string values across all API configurations and policies. Values can be expressions or secrets (never displayed).

<!-- Inbound -->
<set-header name="timeheader" exists-action="override">
    <value>{{TimeNow}}</value>
</set-header>

Delete response headers

A frequent requirement is to remove headers - example those that might leak potential security information

<!-- Outbound -->
<set-header name="x-aspnet-version" exists-action="delete" />
<set-header name="x-powered-by" exists-action="delete" />

Before:

After policy applied:

Amend what’s passed to the backend

Policy expressions can include C# code. Can access a number of .NET Framework types and their members .NET Framework type. A variable named context is implicitly available and its members provide information pertinent to the API request.

More info https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions

<!-- Inbound -->
<set-query-parameter name="x-product-name" exists-action="override">
    <value>@(context.Product.Name)</value>
</set-query-parameter>
<set-header name="x-request-context-data" exists-action="override">
    <value>@(context.User.Id)</value>
    <value>@(context.Deployment.Region)</value>
</set-header>

Note - this trace below was from the Developer portal. I got errors when testing from the Azure Management portal, as the [User Id] is unable to be evaluated.

Send a message to Microsoft Teams channel

It can also be done with Slack

This example shows ‘Send one-way request’ … sends a request to the specified URL without waiting for a response. Another option is to [Send request] and Wait. Complex in-flight processing logic is better handled by using Logic Apps.

For Microsoft Teams

<!-- Outbound -->
<choose>
    <when condition="@(context.Response.StatusCode >= 299)">
        <send-one-way-request mode="new">
            <set-url>https://outlook.office.com/webhook/78f54a63-f217-451a-b263-f1f5c0e866f0@72f988bf-86f1-41af-91ab-2d7cd011db47/IncomingWebh00k/34228a8ccbe94e368d3ac4782adda9b2/4e01c743-d419-49b7-88c6-245e5e31664a</set-url>
            <set-method>POST</set-method>
            <set-body>@{
                    return new JObject(
                        new JProperty("@type","MessageCard"),
                        new JProperty("@context", "http://schema.org/extensions"),
                        new JProperty("summary","Summary"),
                        new JProperty("themeColor", "0075FF"),
                        new JProperty("sections",
                            new JArray (
                                new JObject (
                                    new JProperty("text","Error - details: [link](http://azure1.org)")
                                    )
                                )
                            )
                        ).ToString();
            }</set-body>
        </send-one-way-request>
    </when>
</choose>

    <when condition="@(context.Response.StatusCode == 200)">

Received notification in the Teams channel:

Aborting the processing

<!-- Inbound -->
<choose>
    <when condition="@(true)">
        <return-response response-variable-name="existing response variable">
            <set-status code="599" reason="failure" />
            <set-header name="failure" exists-action="override">
                <value>failure</value>
            </set-header>
            <set-body>blah</set-body>
        </return-response>
    </when>
</choose>


Home | Prev | Next