Skip to content

Commit 1e49835

Browse files
feat(apim): refactor caching policy by operation definition (#877)
1 parent 419e27c commit 1e49835

File tree

3 files changed

+28
-119
lines changed

3 files changed

+28
-119
lines changed

src/lib/azure/services/api-management/main.ts

Lines changed: 23 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
DataAzurermApiManagementConfig,
55
} from '@cdktf/provider-azurerm/lib/data-azurerm-api-management'
66
import { ApiManagementCustomDomain } from '@cdktf/provider-azurerm/lib/api-management-custom-domain'
7-
import { ApiManagementBackend } from '@cdktf/provider-azurerm/lib/api-management-backend'
87
import { ApiManagement } from '@cdktf/provider-azurerm/lib/api-management'
98
import { ApiManagementApi } from '@cdktf/provider-azurerm/lib/api-management-api'
109
import { ApiManagementApiOperation } from '@cdktf/provider-azurerm/lib/api-management-api-operation'
@@ -20,7 +19,6 @@ import {
2019
ApiManagementProps,
2120
ApiManagementBackendProps,
2221
ApiManagementApiProps,
23-
ApiManagementV2Props,
2422
ApiManagementCustomDomainProps,
2523
} from './types'
2624
import _ from 'lodash'
@@ -122,82 +120,6 @@ export class AzureApiManagementManager {
122120
return apiManagement
123121
}
124122

125-
/**
126-
* @summary Method to create a new api management
127-
* @param id scoped id of the resource
128-
* @param scope scope in which this resource is defined
129-
* @param props api management properties
130-
* @see [CDKTF Api management Module]{@link https://github.com/cdktf/cdktf-provider-azurerm/blob/main/docs/apiManagement.typescript.md}
131-
*/
132-
public createApiManagementv2(
133-
id: string,
134-
scope: CommonAzureConstruct,
135-
props: ApiManagementV2Props,
136-
applicationInsightsKey?: ApiManagementLoggerApplicationInsights['instrumentationKey']
137-
) {
138-
if (!props) throw `Props undefined for ${id}`
139-
140-
const resourceGroup = new DataAzurermResourceGroup(scope, `${id}-am-rg`, {
141-
name: scope.props.resourceGroupName
142-
? scope.resourceNameFormatter.format(scope.props.resourceGroupName)
143-
: `${props.resourceGroupName}`,
144-
})
145-
146-
if (!resourceGroup) throw `Resource group undefined for ${id}`
147-
148-
const apiManagement = new Resource(scope, `${id}-am`, {
149-
type: 'Microsoft.ApiManagement/service@2024-05-01',
150-
name: scope.resourceNameFormatter.format(props.name, scope.props.resourceNameOptions?.apiManagement),
151-
location: resourceGroup.location,
152-
parentId: resourceGroup.id,
153-
154-
body: {
155-
properties: {
156-
apiVersionConstraint: {
157-
minApiVersion: '2019-12-01',
158-
},
159-
publisherName: props.publisherName,
160-
publisherEmail: props.publisherEmail,
161-
},
162-
sku: {
163-
capacity: 1,
164-
name: props.skuName,
165-
},
166-
},
167-
168-
responseExportValues: ['*'],
169-
170-
identity: [
171-
{
172-
type: 'SystemAssigned',
173-
},
174-
],
175-
176-
ignoreMissingProperty: true,
177-
ignoreCasing: true,
178-
schemaValidationEnabled: false,
179-
180-
lifecycle: props.lifecycle,
181-
})
182-
183-
if (applicationInsightsKey) {
184-
new ApiManagementLogger(scope, `${id}-am-logger`, {
185-
name: scope.resourceNameFormatter.format(props.name, scope.props.resourceNameOptions?.apiManagementLogger),
186-
resourceGroupName: resourceGroup.name,
187-
apiManagementName: apiManagement.name,
188-
applicationInsights: {
189-
instrumentationKey: applicationInsightsKey,
190-
},
191-
})
192-
}
193-
194-
createAzureTfOutput(`${id}-apiManagementName`, scope, apiManagement.name)
195-
createAzureTfOutput(`${id}-apiManagementFriendlyUniqueId`, scope, apiManagement.friendlyUniqueId)
196-
createAzureTfOutput(`${id}-apiManagementId`, scope, apiManagement.id)
197-
198-
return apiManagement
199-
}
200-
201123
/**
202124
* @summary Method to create a new api management backend
203125
* @param id scoped id of the resource
@@ -301,12 +223,13 @@ export class AzureApiManagementManager {
301223
createAzureTfOutput(`${id}-${operation.displayName}-${operation.method}-apimOperationId`, scope, apimOperation.id)
302224

303225
// Define Caching Policy if enabled
304-
let cacheInboundPolicy = ''
305-
let cacheOutboundPolicy = ''
226+
let cacheSetVariablePolicy = ''
227+
let cacheInvalidateInboundPolicy = ''
228+
let cacheSetInboundPolicy = ''
229+
let cacheSetOutboundPolicy = ''
306230

307-
if (props.caching?.enabled === true) {
308-
if (operation.method === 'get') {
309-
cacheInboundPolicy = `<!-- Generate a comprehensive custom cache key (without query params or Accept header) -->
231+
if (operation.caching) {
232+
cacheSetVariablePolicy = `<!-- Generate a comprehensive custom cache key (without query params or Accept header) -->
310233
<set-variable name="customCacheKey" value="@{
311234
// Instance identification
312235
@@ -316,13 +239,16 @@ export class AzureApiManagementManager {
316239
317240
// Full path construction (without query parameters)
318241
string fullPath = context.Request.Url.Path.ToLower();
319-
242+
243+
// Query parameters
244+
string query = context.Request.Url.Query.ToLower();
245+
320246
// Construct final cache key (no Accept header needed for JSON-only APIs)
321-
return $"{apiName}:{apiVersion}:{fullPath}";
322-
}" />
323-
<set-variable name="bypassCache" value="@(context.Request.Headers.GetValueOrDefault("X-Bypass-Cache", "false").ToLower())" />
247+
return $"{apiName}:{apiVersion}:{fullPath}:{query}";
248+
}" />`
324249

325-
<choose>
250+
if (operation.caching.enableCacheSet) {
251+
cacheSetInboundPolicy = `<choose>
326252
<when condition="@((string)context.Variables["bypassCache"] != "true")">
327253
<!-- Attempt to retrieve cached response -->
328254
<cache-lookup-value key="@((string)context.Variables["customCacheKey"])" variable-name="cachedResponse" />
@@ -347,12 +273,12 @@ export class AzureApiManagementManager {
347273
</choose>
348274
</when>
349275
</choose>`
350-
cacheOutboundPolicy = `<choose>
276+
cacheSetOutboundPolicy = `<choose>
351277
<when condition="@((string)context.Variables["bypassCache"] != "true")">
352278
<!-- Store the response body in cache -->
353279
<choose>
354280
<when condition="@(context.Response.StatusCode == 200)">
355-
<cache-store-value key="@((string)context.Variables["customCacheKey"])" value="@(context.Response.Body.As<string>(preserveContent: true))" duration="${props.caching.ttlInSecs ?? 900}" />
281+
<cache-store-value key="@((string)context.Variables["customCacheKey"])" value="@(context.Response.Body.As<string>(preserveContent: true))" duration="${operation.caching.ttlInSecs ?? 900}" />
356282
<!-- Add cache status header -->
357283
<set-header name="X-Apim-Cache-Status" exists-action="override">
358284
<value>MISS</value>
@@ -370,26 +296,8 @@ export class AzureApiManagementManager {
370296
</choose>`
371297
}
372298

373-
if (operation.method === 'post') {
374-
cacheInboundPolicy = `<!-- Generate a comprehensive custom cache key (without query params or Accept header) -->
375-
<set-variable name="customCacheKey" value="@{
376-
// Instance identification
377-
378-
// API identification
379-
string apiName = context.Api.Name.Replace(" ", "").ToLower();
380-
string apiVersion = context.Api.Version ?? "v1";
381-
382-
// Full path construction (without query parameters)
383-
string fullPath = context.Request.Url.Path.ToLower();
384-
385-
// Query arameters
386-
string query = context.Request.Url.Query.ToLower();
387-
388-
// Construct final cache key (no Accept header needed for JSON-only APIs)
389-
return $"{apiName}:{apiVersion}:{fullPath}:{query}";
390-
}" />
391-
<set-variable name="clearCache" value="@(context.Request.Headers.GetValueOrDefault("X-Apim-Clear-Cache", "false").ToLower())" />
392-
299+
if (operation.caching.enableCacheInvalidation) {
300+
cacheInvalidateInboundPolicy = `<set-variable name="clearCache" value="@(context.Request.Headers.GetValueOrDefault("X-Apim-Clear-Cache", "false").ToLower())" />
393301
<!-- Allow admin to clear specific cache entries -->
394302
<choose>
395303
<when condition="@((string)context.Variables["clearCache"] == "true")">
@@ -408,19 +316,22 @@ export class AzureApiManagementManager {
408316
if (props.rateLimit && scope.props.subscriptionId) {
409317
rateLimitPolicy = `<rate-limit-by-key calls="${props.rateLimit.calls}" renewal-period="${props.rateLimit.renewalPeriodInSecs}" counter-key="${scope.props.subscriptionId}-${apimOperation.operationId}"/>`
410318
}
319+
411320
const policyXmlContent = `<policies>
412321
<inbound>
413322
<base />
414323
${rateLimitPolicy}
415-
${cacheInboundPolicy}
324+
${cacheSetVariablePolicy}
325+
${cacheInvalidateInboundPolicy}
326+
${cacheSetInboundPolicy}
416327
${props.commonInboundPolicyXml ?? ''}
417328
</inbound>
418329
<backend>
419330
<base />
420331
</backend>
421332
<outbound>
422333
<base />
423-
${cacheOutboundPolicy ?? ''}
334+
${cacheSetOutboundPolicy}
424335
${props.commonOutboundPolicyXml ?? ''}
425336
</outbound>
426337
<on-error>

src/lib/azure/services/api-management/types.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,16 @@ export interface ApiManagementApiProps extends ApiManagementApiConfig {
1818
operations: ApiManagementApiOperationProps[]
1919
commonInboundPolicyXml: string
2020
commonOutboundPolicyXml: string
21-
caching?: ApiManagementApiCaching
2221
rateLimit?: ApiManagementApiRateLimit
2322
}
2423

25-
export interface ApiManagementV2Props extends ApiManagementConfig {
26-
body: any
24+
export interface ApiManagementApiOperationProps extends ApiManagementApiOperationConfig {
25+
caching?: ApiManagementApiCaching
2726
}
2827

29-
export interface ApiManagementApiOperationProps extends ApiManagementApiOperationConfig {}
30-
3128
export interface ApiManagementApiCaching {
32-
enabled: boolean
29+
enableCacheSet?: boolean
30+
enableCacheInvalidation?: boolean
3331
ttlInSecs?: number
3432
}
3533

src/test/azure/services/api-management-manager.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ describe('TestAzureApiManagementConstruct', () => {
256256
'${azurerm_api_management_api_operation.test-api-management-dev-apim-api-operation-test-get.operation_id}',
257257
resource_group_name: '${azurerm_api_management_api.test-api-management-dev-am-api.resource_group_name}',
258258
xml_content:
259-
'<policies>\n <inbound>\n <base />\n <rate-limit-by-key calls=\"25\" renewal-period=\"1\" counter-key=\"subscriptionId-${azurerm_api_management_api_operation.test-api-management-dev-apim-api-operation-test-get.operation_id}\"/>\n \n <set-backend-service id=\"apim-generated-policy\" backend-id=\"${azapi_resource.test-api-management-dev-am-be.name}\" />\n </inbound>\n <backend>\n <base />\n </backend>\n <outbound>\n <base />\n \n \n </outbound>\n <on-error>\n <base />\n </on-error>\n </policies>',
259+
'<policies>\n <inbound>\n <base />\n <rate-limit-by-key calls="25" renewal-period="1" counter-key="subscriptionId-${azurerm_api_management_api_operation.test-api-management-dev-apim-api-operation-test-get.operation_id}"/>\n \n \n \n <set-backend-service id="apim-generated-policy" backend-id="${azapi_resource.test-api-management-dev-am-be.name}" />\n </inbound>\n <backend>\n <base />\n </backend>\n <outbound>\n <base />\n \n \n </outbound>\n <on-error>\n <base />\n </on-error>\n </policies>',
260260
})
261261
})
262262
})

0 commit comments

Comments
 (0)