Azure API Management
Policy voorbeelden
Plaats het fragment op de inbound policy van de DEV operatie of API. APIM roept de resolver altijd met GET aan.
`testId` komt standaard uit de query string en valt terug op `default`.
Resolver `problem+json` responses worden direct teruggegeven; gemockte errors zitten in de normale envelope.
Client ID en secret
APIM haalt eerst via client credentials een Entra token op en roept daarna de mock resolver aan.
Named Values
mock-api-base-urlmock-api-tenant-idmock-api-client-idmock-api-client-secretmock-api-scope
Prerequisites
- Maak een confidential client app registration voor APIM.
- Zet de client secret als secret named value, bij voorkeur Key Vault backed.
- Wijs de backend app role Mock.Read toe aan de client app service principal.
- Het access token wordt gecached tot vlak voor de JWT expiration time, per tenant, client id en scope.
<policies>
<inbound>
<base />
<set-variable name="mockApiName" value="@(context.Api.Name)" />
<set-variable name="mockOperationId" value="@(context.Operation.Id)" />
<set-variable name="mockMethod" value="@((context.Request.Method ?? "GET").ToUpperInvariant())" />
<set-variable name="mockTestId" value="@((string)context.Request.Url.Query.GetValueOrDefault("testId", "default"))" />
<set-variable name="mockTokenCacheKey" value="@("mock-resolver-token-{{mock-api-tenant-id}}-{{mock-api-client-id}}-{{mock-api-scope}}")" />
<cache-lookup-value key="@((string)context.Variables["mockTokenCacheKey"])" variable-name="mockAccessToken" />
<rate-limit-by-key calls="20" renewal-period="60" counter-key="@((string)context.Variables["mockTokenCacheKey"])" />
<choose>
<when condition="@(!context.Variables.ContainsKey("mockAccessToken"))">
<send-request mode="new" response-variable-name="mockTokenResponse" timeout="10" ignore-error="false">
<set-url>https://login.microsoftonline.com/{{mock-api-tenant-id}}/oauth2/v2.0/token</set-url>
<set-method>POST</set-method>
<set-header name="Content-Type" exists-action="override">
<value>application/x-www-form-urlencoded</value>
</set-header>
<set-body>@{
return "client_id=" + Uri.EscapeDataString("{{mock-api-client-id}}")
+ "&client_secret=" + Uri.EscapeDataString("{{mock-api-client-secret}}")
+ "&scope=" + Uri.EscapeDataString("{{mock-api-scope}}")
+ "&grant_type=client_credentials";
}</set-body>
</send-request>
<set-variable name="mockAccessToken" value="@(((IResponse)context.Variables["mockTokenResponse"]).Body.As<JObject>()["access_token"].ToString())" />
<set-variable name="mockTokenCacheDuration" value="@{
var jwt = ((string)context.Variables["mockAccessToken"]).AsJwt();
if (jwt == null || !jwt.ExpirationTime.HasValue)
{
return 300;
}
var secondsUntilExpiry = (int)Math.Floor((jwt.ExpirationTime.Value.ToUniversalTime() - DateTime.UtcNow).TotalSeconds);
return Math.Max(60, Math.Min(secondsUntilExpiry - 120, 3300));
}" />
<cache-store-value key="@((string)context.Variables["mockTokenCacheKey"])" value="@((string)context.Variables["mockAccessToken"])" duration="@((int)context.Variables["mockTokenCacheDuration"])" />
</when>
</choose>
<send-request mode="new" response-variable-name="mockResolverResponse" timeout="20" ignore-error="true">
<set-url>@{
var apiName = Uri.EscapeDataString((string)context.Variables["mockApiName"]);
var operationId = Uri.EscapeDataString((string)context.Variables["mockOperationId"]);
var method = Uri.EscapeDataString((string)context.Variables["mockMethod"]);
var testId = Uri.EscapeDataString((string)context.Variables["mockTestId"]);
return $"{{mock-api-base-url}}/api/mock-responses/{apiName}/{operationId}/{method}/{testId}";
}</set-url>
<set-method>GET</set-method>
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + (string)context.Variables["mockAccessToken"])</value>
</set-header>
<set-header name="Accept" exists-action="override">
<value>application/json, application/problem+json</value>
</set-header>
</send-request>
<choose>
<when condition="@(((IResponse)context.Variables["mockResolverResponse"]).StatusCode >= 400)">
<return-response response-variable-name="mockResolverResponse" />
</when>
<otherwise>
<set-variable name="mockEnvelope" value="@(((IResponse)context.Variables["mockResolverResponse"]).Body.As<JObject>())" />
<return-response>
<set-status code="@((int)((JObject)context.Variables["mockEnvelope"])["response"]["statusCode"])" />
<set-header name="Content-Type" exists-action="override">
<value>@((string)((JObject)context.Variables["mockEnvelope"])["response"]["contentType"])</value>
</set-header>
<set-header name="x-mock-source" exists-action="override">
<value>@((string)((JObject)context.Variables["mockEnvelope"])["blobPath"])</value>
</set-header>
<set-header name="x-mock-default" exists-action="override">
<value>@(((bool)((JObject)context.Variables["mockEnvelope"])["isDefault"]).ToString().ToLowerInvariant())</value>
</set-header>
<set-body>@{
var envelope = (JObject)context.Variables["mockEnvelope"];
var value = (string)envelope["response"]["payload"]["value"];
return System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(value));
}</set-body>
</return-response>
</otherwise>
</choose>
</inbound>
</policies>APIM managed identity
APIM gebruikt de eigen managed identity om een token voor de backend API te krijgen.
Named Values
mock-api-base-urlmock-api-resource
Prerequisites
- Enable system-assigned of user-assigned managed identity op APIM.
- Wijs de backend app role Mock.Read toe aan de APIM managed identity service principal.
- Gebruik bij user-assigned identity ook client-id op authentication-managed-identity.
<policies>
<inbound>
<base />
<set-variable name="mockApiName" value="@(context.Api.Name)" />
<set-variable name="mockOperationId" value="@(context.Operation.Id)" />
<set-variable name="mockMethod" value="@((context.Request.Method ?? "GET").ToUpperInvariant())" />
<set-variable name="mockTestId" value="@((string)context.Request.Url.Query.GetValueOrDefault("testId", "default"))" />
<send-request mode="new" response-variable-name="mockResolverResponse" timeout="20" ignore-error="true">
<set-url>@{
var apiName = Uri.EscapeDataString((string)context.Variables["mockApiName"]);
var operationId = Uri.EscapeDataString((string)context.Variables["mockOperationId"]);
var method = Uri.EscapeDataString((string)context.Variables["mockMethod"]);
var testId = Uri.EscapeDataString((string)context.Variables["mockTestId"]);
return $"{{mock-api-base-url}}/api/mock-responses/{apiName}/{operationId}/{method}/{testId}";
}</set-url>
<set-method>GET</set-method>
<authentication-managed-identity resource="{{mock-api-resource}}" />
<set-header name="Accept" exists-action="override">
<value>application/json, application/problem+json</value>
</set-header>
</send-request>
<choose>
<when condition="@(((IResponse)context.Variables["mockResolverResponse"]).StatusCode >= 400)">
<return-response response-variable-name="mockResolverResponse" />
</when>
<otherwise>
<set-variable name="mockEnvelope" value="@(((IResponse)context.Variables["mockResolverResponse"]).Body.As<JObject>())" />
<return-response>
<set-status code="@((int)((JObject)context.Variables["mockEnvelope"])["response"]["statusCode"])" />
<set-header name="Content-Type" exists-action="override">
<value>@((string)((JObject)context.Variables["mockEnvelope"])["response"]["contentType"])</value>
</set-header>
<set-header name="x-mock-source" exists-action="override">
<value>@((string)((JObject)context.Variables["mockEnvelope"])["blobPath"])</value>
</set-header>
<set-header name="x-mock-default" exists-action="override">
<value>@(((bool)((JObject)context.Variables["mockEnvelope"])["isDefault"]).ToString().ToLowerInvariant())</value>
</set-header>
<set-body>@{
var envelope = (JObject)context.Variables["mockEnvelope"];
var value = (string)envelope["response"]["payload"]["value"];
return System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(value));
}</set-body>
</return-response>
</otherwise>
</choose>
</inbound>
</policies>