<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>OpenAPI on Journey through Cloud &amp; Code</title><link>https://gurupasupathy.com/tags/openapi/</link><description>Recent content in OpenAPI on Journey through Cloud &amp; Code</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 20 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://gurupasupathy.com/tags/openapi/index.xml" rel="self" type="application/rss+xml"/><item><title>Managing Azure APIM Operation Policies in Terraform by Importing OpenAPI Specification</title><link>https://gurupasupathy.com/post/2026-02-20_managing-apim-op-policies-in-terraform-by-importing-openapi-spec/</link><pubDate>Fri, 20 Feb 2026 00:00:00 +0000</pubDate><guid>https://gurupasupathy.com/post/2026-02-20_managing-apim-op-policies-in-terraform-by-importing-openapi-spec/</guid><description>&lt;p&gt;&lt;img loading="lazy" src="https://gurupasupathy.com/img/1__mk3hcBMP7jVKBsxWOa5JDA.png"&gt;&lt;/p&gt;
&lt;p&gt;When using Terraform to import an OpenAPI/Swagger definition into Azure API Management (APIM), the API and its operations are created successfully. However, one subtle behavior can cause confusion when trying to manage operation-level policies declaratively.&lt;/p&gt;
&lt;p&gt;This post explains the issue and a simple workaround.&lt;/p&gt;
&lt;h3 id="the-scenario"&gt;The Scenario&lt;/h3&gt;
&lt;p&gt;I was importing my API using Terraform:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Swagger/OpenAPI definition imported into APIM&lt;br&gt;
API created successfully&lt;br&gt;
All operations appeared correctly in Azure&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Later, I wanted to attach operation-level policies using Terraform using &lt;em&gt;azurerm_api_management_api_operation_policy&lt;/em&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p><img loading="lazy" src="/img/1__mk3hcBMP7jVKBsxWOa5JDA.png"></p>
<p>When using Terraform to import an OpenAPI/Swagger definition into Azure API Management (APIM), the API and its operations are created successfully. However, one subtle behavior can cause confusion when trying to manage operation-level policies declaratively.</p>
<p>This post explains the issue and a simple workaround.</p>
<h3 id="the-scenario">The Scenario</h3>
<p>I was importing my API using Terraform:</p>
<blockquote>
<p>Swagger/OpenAPI definition imported into APIM<br>
API created successfully<br>
All operations appeared correctly in Azure</p>
</blockquote>
<p>Later, I wanted to attach operation-level policies using Terraform using <em>azurerm_api_management_api_operation_policy</em></p>
<p>At this point I ran into a problem: <strong>Terraform had no record of the operations in its state file.</strong></p>
<h3 id="why-thishappens">Why This Happens</h3>
<p>This behavior is expected once you understand how Terraform works. Terraform only tracks resources explicitly declared in configuration, or<br>
resources manually imported into state</p>
<p>When Swagger is imported via <em>azurerm_api_management_api</em> the operations are created inside Azure, but they are not separate Terraform-managed resources unless you explicitly declare using <em>azurerm_api_management_api_operation</em></p>
<p>Effectively — API is created in Azure and tracked in Terraform while<br>
API Operations (via Swagger import) are created in Azure but NOT tracked in Terraform</p>
<p>This makes it unclear how to attach policies to those operations without creating the operations explicitly — a nightmare if you have hundreds of operations</p>
<h3 id="the-simple-workaround">The Simple Workaround</h3>
<p>You do not need a Terraform resource reference to the operation for you to create an operation policy and attach it. Instead, you can attach the policy directly using <em>azurerm_api_management_api_operation_policy</em> resource and referencing the Swagger operationId.</p>
<p>Example:</p>
<p>resource &ldquo;azurerm_api_management_api_operation_policy&rdquo; &ldquo;my_op_policy&rdquo; {<br>
provider = &laquo;provider&raquo;<br>
api_name = &ldquo;<your api name>&rdquo;<br>
api_management_name = data.azurerm_api_management.apim.name<br>
resource_group_name = data.azurerm_api_management.apim.resource_group_name<br>
operation_id = &ldquo;<operationId from swagger>&rdquo;<br>
xml_content = templatefile(&quot;<policy path>&quot;, {<br>
backend_name = &ldquo;<backend name>&rdquo;<br>
method = &ldquo;<operation method>&rdquo;<br>
})<br>
}</p>
<p>As long as the API exists in APIM and the operation exists and operation_id exactly matches the Swagger operationId — Terraform can apply and update the policy successfully. No explicit Terraform operation resource is required.</p>
<h3 id="notes">Notes</h3>
<p>1. Use the Swagger operationId, not the display name. Terraform identifies the operation strictly by operationId.</p>
<p>2. Treat operationId as a stable contract. If you later rename the operationId or remove an endpoint or restructure the Swagger Terraform may fail because the referenced operation no longer exists.</p>
<p>3. Importing operations individually is possible but rarely worth it. You can define <em>azurerm_api_management_api_operation</em> and import each operation manually into Terraform state. However, it requires one resource per operation. Also, manual imports are tedious and scales poorly for large APIs thus defeating the benefit of Swagger-driven API definition</p>
<p>For most setups, referencing operationId directly in the policy resource is simpler.</p>
<h3 id="takeaway">Takeaway</h3>
<p>When importing Swagger into APIM using Terraform:</p>
<blockquote>
<p>Operations are created in Azure<br>
Terraform does not automatically track them<br>
Operation policies can still be managed declaratively by simply referencing the Swagger/OpenAPI Spec operationId</p>
</blockquote>
<p>Understanding this distinction can save significant time when automating API Management deployments.</p>
]]></content:encoded></item></channel></rss>