Azure & Serverless

Azure API Management: Gateway Patterns for Microservices

13 min read
#azure#api-management#gateway#microservices
Georg Pfeiffer
Georg Pfeiffer
Senior Solution Architect

Azure API Management sits between your clients and your backend services, handling authentication, rate limiting, transformation, and monitoring. After implementing APIM as the gateway for a microservice-based integration platform, here's what I learned about making it work in practice.

Why an API Gateway?

When you have multiple microservices, each with its own API, clients face:

  • Multiple endpoints to discover and manage
  • Inconsistent authentication across services
  • No centralized rate limiting or throttling
  • Duplicated cross-cutting concerns in every service

An API gateway solves these by providing a single entry point:

text
Client → API Management → Service A
                        → Service B
                        → Service C

Setting Up Products and Subscriptions

APIM organizes APIs into products. Each product has its own subscription keys, rate limits, and access policies:

xml
<!-- product policy: 100 calls per minute, 1000 per hour -->
<rate-limit calls="100" renewal-period="60" />
<quota calls="1000" renewal-period="3600" />

In our integration platform, we created separate products for each consuming application:

  • **CRM Integration** — higher rate limits, access to customer and order APIs
  • **Reporting** — read-only access, lower priority, access to analytics APIs
  • **Partner Portal** — limited access, strict rate limiting

Inbound Policies for Message Validation

One of the most valuable patterns: validating request payloads at the gateway before they reach your services.

xml
<inbound>
    <validate-content
        unspecified-content-type-action="prevent"
        max-size="102400"
        size-exceeded-action="prevent"
        errors-variable-name="validationErrors">
        <content type="application/json"
                 validate-as="json"
                 action="prevent"
                 schema-id="order-schema" />
    </validate-content>
</inbound>

This catches malformed requests before they waste compute on your backend services. In our case, it eliminated 15% of error responses that were caused by invalid payloads from a partner system.

Request Transformation

Different consumers often need different data formats. Instead of building transformation logic into each service, handle it at the gateway:

xml
<outbound>
    <set-body>@{
        var body = context.Response.Body.As<JObject>();
        // transform snake_case to camelCase for legacy consumer
        return JsonConvert.SerializeObject(body,
            new JsonSerializerSettings {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            });
    }</set-body>
</outbound>

Caching for Read-Heavy APIs

For APIs with high read-to-write ratios, APIM's built-in caching dramatically reduces backend load:

xml
<inbound>
    <cache-lookup vary-by-developer="false"
                  vary-by-developer-groups="false"
                  vary-by-query-parameter="status,category"
                  caching-type="internal">
        <vary-by-header>Accept</vary-by-header>
    </cache-lookup>
</inbound>
<outbound>
    <cache-store duration="300" />
</outbound>

In our reporting APIs, this reduced backend calls by 80% during peak hours.

Monitoring and Diagnostics

APIM integrates with Application Insights for request-level telemetry:

xml
<inbound>
    <set-header name="X-Correlation-Id" exists-action="skip">
        <value>@(context.RequestId.ToString())</value>
    </set-header>
    <trace source="gateway"
           severity="information">
        <message>@($"Request from {context.Subscription.Name}")</message>
    </trace>
</inbound>

Every request gets a correlation ID that flows through to backend services, making distributed tracing across the entire pipeline possible.

Versioning Strategy

APIs evolve. APIM supports multiple versioning schemes — we use URL path versioning:

text
/api/v1/orders    → Backend v1
/api/v2/orders    → Backend v2

Both versions can run simultaneously. When a consumer migrates to v2, we don't break their existing integration. When all consumers have migrated, we deprecate v1 with a sunset header:

xml
<outbound>
    <set-header name="Sunset" exists-action="override">
        <value>Sat, 01 Mar 2026 00:00:00 GMT</value>
    </set-header>
</outbound>

Key Takeaways

  • Use APIM products to group APIs by consumer and apply different policies
  • Validate payloads at the gateway to protect backend services
  • Leverage caching for read-heavy APIs — the savings are significant
  • Correlation IDs and Application Insights integration are essential for debugging
  • Plan for API versioning from day one — consumers will thank you

Share this article

Georg Pfeiffer

About the Author

Georg is a senior solution architect specializing in .NET, Azure, and Dynamics 365. He helps organizations design and build scalable, maintainable enterprise systems. When he's not writing code, he's writing about it here.

Learn more about Georg

© 2026 georgpfeiffer.dev. All rights reserved.

Built with SvelteKit & Tailwind CSS