Skip to content

Policies

In Azure API Management, you can change API behavior through configuration using policies. Policies are a collection of statements that are run sequentially on the request or response of an API. Read more in the Policies in Azure API Management documentation.

Although you can do quite a lot with policies we recommend that you keep them as simple as possible since we try to follow the principle of smart endpoints and dumb pipes.

Policy files SHOULD be stored in the repo folder src/bicep/policies.

Policies are applied at three levels:

  • Tenant — IMPORTANT! These policies are enforced centrally and SHOULD NOT be set on individual APIs.
  • API — This policy is set on API level and a basic policy has already been setup. Update the apiPolicy.xml located in the repo folder src/bicep/policies/
  • Operation — Theses policies are applied per operation. Use naming standard [operationId]-operationPolicy.xml

An operation policy file need to be connected to the API operator in the bicep file api-definition.bicep located in the repo folder src/bicep/. The connection is done using the operationDefinitions array.

param operationDefinitions array = [
  {
     operationId: '{operation-id}'
     policy: loadTextContent('./policies/{policy-file}')
  }
  {
     operationId: '{another-operation-id}'
     policy: loadTextContent('./policies/{another-policy-file}')
  }
]

In the example below the operation GetSessions is connected with a policy. First, the relevant part of the oas.yaml file:

paths:
  /sessions:
    get:
      tags:
      - sessions
      description: A list of sessions.  Optional parameters work as filters to reduce
        the listed sessions.
      operationId: GetSessions

And then how to define the operationDefinitions array:

param operationDefinitions array = [
  {
     operationId: 'GetSessions'
     policy: loadTextContent('./policies/getsessions-operationPolicy.xml')
  }
]

Ex: getsessions-operationPolicy.xml with grant type Client Credentials

<policies>
    <inbound>
    <base />
        <cache-lookup-value key="@("api0000-demo-conference-sessions-bearerToken")" variable-name="bearerToken" />
        <choose>
            <when condition="@(!context.Variables.ContainsKey("bearerToken-sessions"))">
                <send-request ignore-error="true" timeout="20" response-variable-name="accessTokenResult" mode="new">
                    <set-url>{{api0000-demo-conference-sessions-tokenUrl}}</set-url>
                    <set-method>POST</set-method>
                    <set-header name="Accept" exists-action="override">
                        <value>*/*</value>
                    </set-header>
                    <set-header name="Accept-Encoding" exists-action="override">
                        <value>gzip, deflate, br</value>
                    </set-header>
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/x-www-form-urlencoded</value>
                    </set-header>
                    <set-body>@{
                                return "client_id={{api0000-demo-conference-sessions-client-id}}&client_secret={{api0000-demo-conference-sessions-client-secret}}&scope={{api0000-demo-conference-sessions-scope}}&grant_type=client_credentials";
                        }</set-body>
                </send-request>
                <set-variable name="accessToken" value="@(((IResponse)context.Variables["accessTokenResult"]).Body.As<JObject>())" />
                <set-variable name="bearerToken" value="@((string)((JObject)context.Variables["accessToken"])["access_token"])" />
                <set-variable name="tokenDurationSeconds" value="@((int)((JObject)context.Variables["accessToken"])["expires_in"])" />
                <cache-store-value key="api0000-demo-conference-sessions-bearerToken" value="@((string)context.Variables["bearerToken"])" duration="@((int)context.Variables["tokenDurationSeconds"])" />
            </when>
        </choose>
        <set-header name="Authorization" exists-action="override">
            <value>@("Bearer " + (string)context.Variables["bearerToken"])</value>
        </set-header>
    <set-backend-service backend-id="api0000-demo-conference-sessions" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
        <choose>
            <when condition="@(context.Response.StatusCode == 401 || context.Response.StatusCode == 403)">
                <cache-remove-value key="api0000-demo-conference-sessions-bearerToken" />
            </when>
        </choose>    
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

See Azure API Management Policy Snippets for more information about snippets.