Microservices Integration Patterns on Azure Functions

Most integration estates do not fail because someone picked the wrong queue product. They fail because every project rebuilds the same verbs—file drop, route, transform, deliver—with slightly different code, different secrets handling, and no shared ops story.

Microservices integration patterns here means a small set of capability connectors—each with one clear job—that you compose into project-specific flows through configuration, not copy-paste. This post is the map: config-driven Azure Functions connectors that behave like Lego blocks (or Boomi-style connectors you own).

Engineers get contracts and named enterprise patterns. Engineering managers get one scoreboard: how many integrations share versioned artifacts versus how many are one-off snowflakes. Deep implementation of each connector lands in later posts; here we stay at the catalog level—with diagrams you can actually defend in a design review.

Config-driven means: one versioned Function artifact, many deployments, partner variance stays in config—not a fork of the C# for every SFTP partner.

Source of truth for this series: the public reference implementation at github.com/fransiscuss/integration-azure (commit a24bc48 on main when this revision shipped). Connector names, triggers, and config shapes below track that repo—not a fictional catalog. Later deep dives pull real C# and YAML from the same tree.

What microservices integration patterns means here

Stop rebuilding partner plumbing. Package integration verbs as small connectors and compose them like Lego with configuration.

If you have ever shipped a game engine plus mods, or an npm package plus appsettings, you already know the shape:

  • The engine (template repo) ships the connectors once—SFTP pick-up, HTTP facade, transform, and the rest.
  • Each new partner is mostly a mod config: routes, maps, schedules, Key Vault refs—not a fork of Unity.
  • The message bus is the job queue between steps.
  • Claim-check is sending a link to a blob instead of stuffing a 200 MB file through chat.

Enterprise integration is that pain at partner scale. If every class project reimplemented “upload CSV → parse → call REST” with different logging and secrets, you would hate senior year. Production does the same thing with higher blast radius.

Partners outside Azure; Front Door, API Management, facade, publish, Service Bus, Event Grid, thirteen connectors including delivery, Blob, Cosmos, Key Vault, domain services
Shared Function artifacts and per-project config on a Service Bus spine. Partners sit outside Azure. Blob claim-check; Cosmos multi-connector ledger; Key Vault estate-wide via MI. Includes delivery. Click image to zoom.

Why I use config-driven Azure Functions integration

Model What you change per project What you pay later
Bespoke per partner Code, pipelines, logging, security reviews N× maintenance; every CVE is a scavenger hunt
Central iPaaS only Flows inside the vendor License + lock-in; hard custom edges
Config-driven Functions Config, Key Vault refs, route/map bindings One shared release train; variance stays declarative

Managed Azure still owns the spine: messaging, storage, identity. Connectors own the domain-shaped verbs vendors never ship exactly your way.

Architecture you can draw on a whiteboard

Reference host: .NET isolated Azure Functions—one trigger per connector. Container Apps or AKS are fine if that is already your standard; they are not my default story here.

Piece Role
Service Bus Small pipeline envelopes (peek-lock, DLQ, scheduled redelivery)
Blob Storage Large payloads + YAML/JSON maps (claim-check)
Cosmos DB Idempotency ledger + optional ordering gate
Managed identity Access Azure resources—no connection strings next to maps
Event Grid Edge when ingress is event-shaped
APIM / Front Door Product edge in front of Facade

Deployment rule I keep repeating: one versioned Function artifact × many deployments with different configuration. CI builds packages from the template repo. Project pipelines should not fork C# per partner.

Config I actually ship:

  1. App settings — binding names, feature toggles
  2. Key Vault references — secrets
  3. Blob YAML/JSON — routes, maps, partner profiles
  4. Azure App Configuration later for flags if needed—not the base pattern

Claim-check and the pipeline envelope

Connectors share one contract: a small envelope on Service Bus and large content off-bus. That is the Claim-Check pattern—store the payload externally and pass a reference through messaging. In this design the reference is a blobLocation next to CloudEvents-friendly metadata.

{
  "specversion": "1.0",
  "id": "msg-7f3c2a1e-9b44-4d2f-a1c0-0e8f2b6d1a55",
  "type": "integration.pipeline.step",
  "source": "connectors/publish",
  "time": "2026-08-06T01:12:44Z",
  "datacontenttype": "application/json",
  "data": {
    "correlation": {
      "business": {
        "publisherId": "partner-acme",
        "interfaceId": "nightly-inventory",
        "fileId": "INV_20260806_0112.csv"
      }
    },
    "blobLocation": {
      "container": "pipeline-payloads",
      "path": "acme/nightly-inventory/2026/08/06/msg-7f3c2a1e.csv",
      "contentType": "text/csv"
    },
    "step": "published"
  }
}

Tracing note: carry W3C traceparent on the transport (Service Bus application properties / HTTP headers)—not nested under business correlation in data. Business keys stay in data.correlation.business.

On-call tip that saves arguments: separate W3C traceparent (distributed tracing) from business correlation (publisher / interface / file id). Ops and partner support query different axes without conflating them.

Facade vs API gateway — direction matters

Client outside Azure to Azure Front Door to Azure API Management to Facade branching to Event Grid or Service Bus
HTTP direction of travel: Client → Azure Front Door → API Management (product edge) → Facade Functions (application edge) → Event Grid or Service Bus. Do not put Facade in front of APIM. Click image to zoom.
Layer Owns
APIM / Front Door Throttling, quotas, product policies
Facade (HTTP Function) Route match, auth handoff, schema validation, envelope mapping, response shape

When Event Grid wins vs Service Bus after Facade: choose Event Grid for event-shaped fan-out to many Azure-native subscribers. Choose Service Bus when you need a work queue—peek-lock, competing consumers, scheduled redelivery, and a first-class dead-letter queue. Config picks the path; exclusive OR per interface, not always both.

Facade is the config-driven application edge. Do not invert the mental model into “Facade talks outward to APIM.” For the deep dive on that edge, see Building a Config-Driven API Facade on Azure Functions.

routes:
  - name: submit-order
    match: { method: POST, path: /v1/orders }
    auth: { requiredScopes: ["orders.submit"] }
    validate: { schemaRef: blob://config/schemas/order-submit.v1.json }
    map:
      cloudEventType: integration.order.submitted
      busEntity: sbq-orders-in
    idempotency: { header: Idempotency-Key, ttlHours: 24 }

Enterprise patterns → eight families, thirteen connectors

Managers hear a short list of reusable verbs. Engineers ship eight capability families as thirteen versioned Function apps—verbs for slides, catalog IDs for repos.

Family Connectors Job
API ingress facade HTTP edge: validate, map, emit envelope
SFTP ingress publish Poll SFTP, stage blob, publish envelope
Routing subscription Content-based when/then/otherwise
Inbound prep preprocessing, decompress Normalize / unpack
Transformation transformation CSV / JSON / XSLT / HTTP maps
Outbound prep compress, postprocessing Pack / partner finishers
SFTP egress sender, sequence, delivery Ordered push + completion
HTTP egress apidelivery, webhookdelivery Paged REST + webhooks

PGP and archive steps sit as adapters on prepare/transform edges. Resist inventing connector fourteen when a config profile on transformation or apidelivery would do.

Example compositions

  • Inbound file: publish → decompress → transformation → subscription → domain
  • Inbound HTTP: Client → APIM/FD → facade → Service Bus → subscription → …
  • Outbound: domain → transformation → compress → (sequence?) → sender or apidelivery

The chain is not sacred. The invariant is the same versioned artifact with different configuration across projects.

Enterprise integration patterns → repo realization

Classic EIP names, not proprietary product terms—mapped to the connectors in this catalog:

Integration pattern Repository realization
API Gateway / Facade Config-driven HTTP ingress in facade
Canonical message model Pipeline envelope + CloudEvents metadata
Claim-check Service Bus carries blobLocation; payloads stay in Blob
Polling consumer Scheduled SFTP pickup in publish
Content-based router Declarative when/then/otherwise in subscription
Message translator CSV/JSON/XSLT/HTTP in transformation
Idempotent receiver Stable message IDs, Cosmos ledger, Facade keys
Dead-letter channel Native Service Bus dead-lettering
Resequencer Cosmos-backed ordering gate in sequence
Protocol adapter SFTP, REST, webhook, PGP, archive connectors

Reliability language for design reviews

Term Meaning here
Delivery At-least-once from Service Bus and Function triggers—not exactly-once transport
Effect Effectively-once business outcome via deterministic IDs, idempotent writes, Cosmos ledger
Retries Broker-scheduled redelivery—not Thread.Sleep while holding a peek-lock
Poison After the retry budget → Service Bus dead-letter queue with a filterable reason

If you market “exactly-once” to stakeholders, you lose trust the first time a network blip redelivers a message. Market the ledger and the DLQ playbook instead.

Ordinary connectors scale as competing consumers. Ordering is a feature flag on an interface—you pay concurrency and head-of-line blocking only when the partner contract requires it.

Scoreboard: is this a platform or a folder of repos?

Role Healthy signal
Product Next partner is mostly config + UAT, not greenfield Functions
Eng manager One template repo; SLOs; DLQ runbooks; kill switches per connector
Engineer Project logic lives in versioned config and small extension points—not forks

Metrics I actually care about:

  • Percent of partner onboardings with zero new connector code
  • Mean time to roll a security patch across deployments
  • Dead-letter rate by connector and config profile
  • Count of forked repos still claiming to be “the SFTP service”

Trade-offs I accept on purpose

Choice You gain You accept
At-least-once Simple brokers, horizontal scale, honest failures You must design idempotency; duplicates happen
Config compatibility Many projects on one artifact train Schema breaks need versioning discipline
Ordering Partner sequence contracts Lower concurrency; head-of-line risk
Shared releases One CVE fix lifts many interfaces Bad shared release has blast radius—canary and config freeze matter

This is not a full ESB revival. Domain services stay domain services. It is not “Functions for everything”—three quiet integrations a year may win with a smaller shared library. It is not a substitute for security review; shared crypto and edge connectors concentrate risk usefully, and you still rotate keys and classify data.

Rules that keep the model honest

  1. Partner endpoints, maps, schedules, crypto profiles → config change
  2. New capability or shared fix → code change
  3. Config is PR’d and promoted like code
  4. Secrets never sit beside maps
  5. A “just this once” fork is a platform failure—extract an extension point
  6. Envelope or map schema changes are versioned events, not silent renames

Structural mapping lives in transformation. Pricing, eligibility, and workflow decisions live in domain services. Connectors fail closed on contract and security errors; they should not silently “fix” business outcomes.

FAQ

What is config-driven Azure Functions integration in plain language?

Reusable integration capabilities—ingress, route, transform, deliver—deployed as separate Function apps and composed with messaging and configuration, instead of rebuilding the same plumbing in every project.

How is this different from Boomi or another iPaaS?

Same connector-and-map product metaphor. You own the code, runtime, and data path on Azure. Some teams mix both: iPaaS for commodity SaaS glue, owned connectors for regulated or high-volume edges.

Why Azure Functions instead of Container Apps or AKS?

Functions match one-trigger connectors, competing consumers on Service Bus, and sparse or bursty partner traffic without forcing a full cluster ops model. Use AKS or Container Apps when the organisation already runs everything there.

Is delivery exactly-once?

No. The platform is at-least-once. Exactly-once effects come from deterministic IDs, idempotent handlers, and the Cosmos ledger—not from pretending the broker never redelivers.

Where should business rules live?

Not inside an SFTP sender or a blind transformer. Keep structural mapping in transformation; keep pricing and eligibility in domain services.

Where is the reference code?

In fransiscuss/integration-azure on GitHub: one folder per connector under functions/, shared libraries under shared/, and composition via integrations/*.yaml. This post is the map; the repo is the buildable template.

Closing

Strong microservices integration patterns on Azure are less about drawing more boxes and more about refusing to rewrite SFTP, routing, transform, and HTTP egress for the fifteenth time. Start with the eight capability families and thirteen connectors. Publish the envelope contract. Separate traces from business correlation. Put claim-check on the bus. Design for at-least-once with a ledger and a DLQ. Promote config like code.

When you need the HTTP edge in depth, start with the Facade API microservice on Azure. For reliable messaging mechanics, see the Service Bus peek-lock guide.

Similar Posts