Adapter
The adapter pattern in cloud-native systems normalizes heterogeneous external interfaces — legacy protocols, varied config formats, different logging APIs — into a consistent in…
Introduction
The adapter pattern in cloud-native systems normalizes heterogeneous external interfaces — legacy protocols, varied config formats, different logging APIs — into a consistent interface the application expects. Amazon's retail services integrate with hundreds of vendor systems, mainframe endpoints, and region-specific payment gateways via adapter containers.
Staff architects deploy adapters as containers that translate between the application's expected contract and the external system's actual interface — without polluting domain code with integration quirks.
Real production story
Amazon's inventory sync integrated with a legacy vendor via SOAP over a VPN tunnel. The vendor changed WSDL quarterly; each change required edits in the inventory service's core domain module. Extracting a dedicated adapter container that exposed a clean gRPC interface internally and handled SOAP/WSDL/retries externally let the inventory team freeze their contract while the adapter team owned vendor churn. When the adapter's memory leak during large catalog syncs OOMKilled the pod, only the sync pipeline stalled — not the real-time inventory API — because adapter ran as a separate deployment, not a sidecar.
Business problem
Business pressure: Amazon retail integrates with diverse vendor inventory systems, payment processors, and regional compliance APIs — each with different protocols, auth, and failure modes. Embedding integration logic in domain services couples product velocity to vendor release schedules.
- Revenue at risk: Vendor API change breaking inventory service deploy blocks catalog updates during peak shopping events.
- Engineering velocity: Domain teams should not become experts in SOAP, EDI, or regional payment gateways.
- Compliance / trust: Payment gateway adapters must isolate PCI scope — card data never reaches domain service.
Architecture overview
A cloud-native adapter is a containerized service that translates between an external system's interface and the application's expected internal contract. It handles protocol conversion, auth, retry, and format mapping.
- Definition: Container normalizing heterogeneous external interfaces to a stable internal API.
- When to adopt: External system protocol differs from internal standard; vendor changes frequently; PCI/compliance boundary needed.
- When to defer: External API already matches internal contract (native gRPC partner) — direct integration is simpler.
- Operability: Adapter error rate, translation latency, vendor API health, and sync lag metrics.
Architecture motivation
Why architects care: The adapter pattern creates an anti-corruption boundary at the infrastructure level. Domain services speak internal gRPC/REST; adapter containers translate to/from external protocols. This is the containerized cousin of Hohpe's anti-corruption layer.
- Force: Multiple external systems with incompatible interfaces feeding one domain model.
- Constraint: Cannot replace vendor systems — must adapt to their contracts.
- Outcome: Adapter as separate deployment with internal API contract, vendor-specific logic isolated, PCI/network boundaries enforced.
Internal architecture
Amazon vendor inventory adapter — separate deployment with internal gRPC:
- Domain service never imports SOAP libraries — only gRPC client to adapter.
- Adapter is separate deployment — vendor OOM/leak does not crash inventory API pods.
- NetworkPolicy restricts vendor VPN access to adapter pods only — smallest PCI/network scope.
Inventory Service (domain)↓ gRPC: GetVendorStock(vendor_id, sku)↓ internal contract (stable protobuf)Adapter Deployment: vendor-acme-adapter (replicas: 2)├─ gRPC server: :50051 (internal contract)├─ translation layer: protobuf ↔ SOAP/XML├─ vendor client: HTTPS + WS-Security auth├─ retry + circuit breaker on vendor calls└─ cache: Redis (vendor catalog, TTL 5m)External: vendor-acme.com SOAP endpoint (VPN)↑ adapter is only component with VPN accessNetworkPolicy: only adapter pod can egress to vendor VPN
Data flow
Request: domain service gRPC call → adapter translates to vendor protocol → vendor response normalized → gRPC response. Sync: adapter polls vendor catalog on schedule, publishes normalized events to internal Kafka topic.
- Write path: Inventory adjustment → adapter → vendor SOAP update with vendor-specific error mapping.
- Read path: gRPC GetVendorStock → adapter checks Redis cache → vendor API on miss.
- Async path: Scheduled catalog sync → adapter polls vendor → publishes VendorCatalogUpdated to Kafka.
// Adapter internal gRPC service (TypeScript)const server = new grpc.Server();server.addService(VendorInventoryService, {async getVendorStock(call, callback) {const { vendorId, sku } = call.request;try {const cached = await redis.get(`stock:${vendorId}:${sku}`);if (cached) return callback(null, JSON.parse(cached));const soapResponse = await vendorClient.getStock(sku); // SOAP + WS-Securityconst normalized = translateToInternal(soapResponse);await redis.setex(`stock:${vendorId}:${sku}`, 300, JSON.stringify(normalized));callback(null, normalized);} catch (err) {const mapped = mapVendorError(err); // vendor error codes → gRPC statuscallback(mapped);}},});// Domain service — only knows gRPC contractconst stock = await vendorInventoryClient.getVendorStock({ vendorId: "acme", sku: "B08N5WRWNW" });
System design diagram
Two diagrams show the Adapter topology and the primary request/event path used in production at scale.
Production code example
Adapter deployment template — Amazon platform standard:
- NetworkPolicy is part of adapter architecture — not optional security add-on.
- Internal gRPC service exposed via ClusterIP — domain services discover via service catalog.
- Vendor credentials in K8s secrets synced from Vault — never in image or env plaintext.
apiVersion: apps/v1kind: Deploymentmetadata:name: vendor-acme-adapterlabels: { pattern: adapter, vendor: acme }spec:replicas: 2template:spec:serviceAccountName: vendor-adaptercontainers:- name: adapterimage: amazon/vendor-acme-adapter@sha256:...ports: [{ containerPort: 50051, name: grpc }]env:- name: VENDOR_ENDPOINTvalueFrom: { secretKeyRef: { name: acme-vendor-creds, key: endpoint } }resources:requests: { cpu: "500m", memory: "512Mi" }---apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: vendor-acme-adapter-egressspec:podSelector: { matchLabels: { vendor: acme } }policyTypes: [Egress]egress:- to: [{ ipBlock: { cidr: 10.50.0.0/16 } }] # vendor VPN onlyports: [{ protocol: TCP, port: 443 }]
Enterprise case study
Amazon — vendor inventory adapter fleet: One adapter deployment per major vendor with stable internal gRPC contract. Vendor WSDL changes require adapter-only deploy — inventory service unchanged for 18 months.
- Before: Vendor changes caused 4 inventory service incidents per year; SOAP libs in domain module.
- Decision: Extract adapter per vendor; internal protobuf contract owned by platform team.
- After: Zero domain service deploys for vendor changes; PCI scope reduced to payment adapter pods.
Trade-offs
- Isolation vs latency: Separate adapter deployment adds network hop (~1-2ms) vs in-process adapter.
- Separate deploy vs sidecar: Deployment isolates failure domains; sidecar shares pod lifecycle but lower latency.
- Cache freshness: Adapter cache reduces vendor load but may serve stale stock — TTL tuned per vendor SLA.
- Maintenance: One adapter per vendor — N vendors = N adapter deployments to operate.
Security considerations
Adapter is the trust boundary: Vendor credentials, VPN access, and PCI-scoped data stay in adapter — never in domain service.
- Identity: Adapter holds vendor API credentials in Vault; domain service uses internal mTLS only.
- Data: Card data stops at payment adapter — domain sees tokenized payment_id only.
- Supply chain: Vendor SDK dependencies isolated in adapter image — not in domain service supply chain.
Scalability analysis
Scale dimensions: Amazon integrates 100k+ vendor SKUs. Adapter sync jobs are batch-heavy; real-time lookups are cache-friendly. Scale adapter replicas independently from domain service.
- Horizontal scale: Adapter replicas scale on gRPC request rate; sync job runs as CronJob separately.
- Hot spots: Popular SKU cache miss floods vendor API — warm cache during sync; per-SKU rate limit.
- Cost: One adapter deployment per vendor — consolidate similar vendors into parameterized adapter where possible.
Failure scenarios
What breaks: Vendor WSDL change breaks adapter parsing; VPN tunnel down isolates adapter; cache serves stale stock during vendor outage.
- Vendor schema change: Adapter returns 500 to domain — circuit breaker + alert adapter team, not inventory team.
- VPN failure: Adapter cannot reach vendor — domain gets UNAVAILABLE; inventory uses last-known cache with staleness flag.
- Stale cache: Vendor stock zero but cache shows available — TTL + event-driven cache invalidation on vendor webhook.
Staff engineer insights
- Adapter is an anti-corruption layer in a container — domain code never imports vendor SDKs.
- Separate deployment over sidecar when vendor failure must not crash domain pods.
- Internal gRPC contract is the platform API — version it like any public API.
- NetworkPolicy to restrict vendor access to adapter pods only — smallest blast radius.
Interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1AdvancedQuestionCloud-native adapter vs anti-corruption layer — same pattern?+
Answer
Follow-up
2AdvancedQuestionAdapter as separate deployment vs sidecar — trade-offs?+
Answer
Follow-up
3AdvancedQuestionHow do you version the internal adapter API contract?+
Answer
Follow-up
4IntermediateQuestionVendor API goes down. What does domain service see?+
Answer
Follow-up
5AdvancedQuestionDesign PCI scope reduction with payment adapter.+
Answer
Follow-up
Architecture review questions
- Domain service imports no vendor-specific SDKs or protocols?
- Internal gRPC/REST contract versioned with compatibility tests?
- NetworkPolicy restricts vendor access to adapter pods only?
- Vendor credentials isolated in adapter — not in domain service?
- Circuit breaker and error mapping from vendor codes to internal status?
- Cache TTL and invalidation strategy documented per vendor?
Summary
The adapter pattern at Amazon scale means one container per external system, a stable internal gRPC contract, NetworkPolicy-isolated vendor access, and domain services that never import vendor SDKs. Adapters absorb external churn so domain teams ship features, not SOAP patches.