SaveMyCert
Log in
5 of 5 free questions left today·for unlimited practice
Development with AWS Services

Application Development Patterns on AWS: Architecture, APIs and Messaging

15 min readDVA-C02 · Development with AWS ServicesUpdated

Developing code for applications hosted on AWS means choosing the architectural pattern, the coupling model, and the integration services that let your code survive real-world failure — and the DVA-C02 exam tests those choices relentlessly. Domain 1 is the heaviest domain at 32% of scored content, and Task 1.1 is its foundation: event-driven architecture, loose coupling, synchronous versus asynchronous communication, and the messaging trio of SQS, SNS, and EventBridge. Exam questions rarely ask for definitions. Instead they hand you a scenario — a checkout service that loses orders when a downstream API fails, a notification that must reach three systems at once — and ask which pattern or service fixes it. This lesson covers every skill in the task: architectural patterns, fault-tolerant code with retries and idempotency, building APIs on API Gateway, messaging and streaming code patterns, EventBridge rules with content filtering, and resilient third-party integrations.

What you’ll learn
  • Choose between monolithic, microservices, and event-driven architectures — and between choreography and orchestration — for a given scenario
  • Design loosely coupled, stateless components that communicate synchronously or asynchronously as the workload demands
  • Write fault-tolerant code using retries with exponential backoff and jitter, idempotency, and dead-letter queues
  • Build and extend APIs on API Gateway with request validation, mapping templates, and status-code overrides
  • Select the right integration service — SQS, SNS, EventBridge, or Kinesis — and write correct code against it with the AWS SDK
  • Harden third-party integrations with timeouts, retry logic, and circuit breakers

Architectural patterns: monolithic, microservices, and event-driven

Architectural patterns describe how an application is divided into deployable parts and how those parts communicate — and the exam expects you to match a pattern to a scenario, not recite definitions. A monolith is one deployable unit: simple to build and test at first, but it scales as a whole, a single defect can take down everything, and every team deploys in lockstep. Microservices split the system into independently deployable services, each owning its logic and data, communicating over APIs or events. Each service scales, fails, and deploys on its own — at the cost of distributed-system complexity. Event-driven architecture takes decoupling further: producers emit events describing what happened, and consumers react. The producer never knows who is listening, so you can add consumers without touching existing code.

Two coordination styles matter within event-driven systems. Choreography has no central controller — each service reacts to events (typically via Amazon EventBridge or Amazon SNS) and emits its own. It maximizes independence but makes the end-to-end flow harder to see. Orchestration puts a central coordinator in charge of the sequence — on AWS that is AWS Step Functions, which holds workflow state, applies per-step retries and error handling, and supports compensation logic. Exam cue: if the scenario needs visibility into a multi-step business process, per-step error handling, or waiting on approvals, pick orchestration with Step Functions; if services should evolve independently and merely react to facts, pick choreography.

Fanout delivers one event to many consumers in parallel: classically an SNS topic pushing to multiple SQS queues, or an EventBridge rule with multiple targets. Giving each consumer its own queue adds durability and independent retry — one slow consumer never blocks the others.

State, coupling, and synchronous versus asynchronous communication

Stateful versus stateless is about where session and workflow data lives. A stateless component keeps nothing about the client between requests — any instance can handle any request, which is what makes horizontal scaling and self-healing possible. State that must survive gets externalized to a database or cache rather than held in instance memory or on local disk. A stateful component pins a client to the instance holding its data: lose the instance, lose the session. The exam treats stateless as the default goal for scalable application tiers.

Tightly coupled components call each other directly and synchronously, so they share fate: if the downstream service is slow or down, the caller degrades with it, and both must scale together. Loosely coupled components put a queue or event bus between themselves. The buffer absorbs traffic spikes, lets each side scale and fail independently, and lets a consumer be offline without losing work.

DimensionSynchronousAsynchronous
Caller experienceWaits for the responseHands off and continues
Failure behaviorDownstream failure surfaces immediately to the callerMessages wait in a buffer; consumers retry later
Typical AWS glueAPI Gateway, direct SDK calls, load balancersSQS, SNS, EventBridge, Kinesis
Best whenThe client needs the answer now (login, price check)Work can complete later (emails, order processing, image resize)

Watch for trigger words: decouple, buffer, absorb spikes, and no data loss during downstream outage all point at an asynchronous, queue-based answer.

Writing fault-tolerant, resilient application code

Fault-tolerant code assumes that remote calls will sometimes fail and handles those failures deliberately instead of crashing or corrupting data. The first tool is the retry — but only for transient errors: throttling responses, 5xx server errors, and network timeouts. Retrying a validation error (a 4xx caused by a bad request) just repeats the failure. Naive immediate retries make outages worse: when a throttled service recovers, every client retries at once and knocks it back over. The fix is exponential backoff — doubling the wait after each attempt — combined with jitter, randomizing each wait so clients do not retry in synchronized waves. The AWS SDKs implement this for you: every client ships with configurable retry behavior (a standard mode with backoff and jitter, and an adaptive mode that also rate-limits the client when it detects throttling), plus a maximum-attempts setting. Know that the SDK retries throttling and 5xx errors automatically; your code adds retries around business operations and non-AWS calls.

Retries create a second obligation: idempotency. Queues and event buses deliver at least once, and retries redeliver, so your consumer will eventually process the same message twice. Design handlers so reprocessing is harmless — carry an idempotency key with each request, record processed keys, and skip or return the stored result on a duplicate rather than charging a card twice.

Finally, plan for messages that can never succeed. A malformed payload will fail every retry forever, blocking a queue — the poison-pill problem. A dead-letter queue receives a message after it has been received more than a configured maxReceiveCount, taking it out of the processing loop so you can inspect, fix, and replay it. Every production queue should have one, plus an alarm on its depth.

Creating and extending APIs with Amazon API Gateway

Creating and extending APIs on AWS centers on Amazon API Gateway, and the exam expects you to know which API type offers which capability. REST APIs carry the full feature set: request validation, request and response transformation with mapping templates, API keys and usage plans, response caching, and fine-grained gateway responses. HTTP APIs are cheaper and lower-latency but are built around proxy integrations — they do not support mapping templates or request validators. When a question mentions transforming payloads or validating requests at the gateway, it is describing a REST API.

Request and response transformation happens in mapping templates, written in Velocity Template Language (VTL) and attached to non-proxy (custom) integrations. A mapping template can reshape a client payload into what a legacy backend expects — or reshape the backend response for clients — without changing code on either side. With a proxy integration, API Gateway passes the request straight through, so any transformation logic must live in your backend code instead.

Enforcing validation rules is the job of request validators: declare required query strings and headers, and attach a JSON Schema model for the body. Invalid requests are rejected with a 400 before they ever reach — or bill — your backend.

Overriding status codes is configured in integration responses. You map patterns in the backend response (for example, a regex over an error message) to the method response status the client should see — turning a backend error string into a clean 404 or 503. Separately, gateway responses let you customize the errors API Gateway itself generates, such as the body and headers of a 403 from a failed authorizer.

Messaging code patterns: SQS, SNS, and the fanout scenario

Messaging services move work between decoupled components, and choosing among them is one of the most common exam decisions.

ServiceModelConsumersPick when
Amazon SQSPull — consumers poll a queueOne consuming application per queue (messages deleted after processing)Buffering work, load leveling, guaranteed processing with retry
Amazon SNSPush — topic delivers to subscribersMany subscribers per topic (SQS, Lambda, HTTP, email, SMS)One event must reach several systems at once
Amazon EventBridgePush — bus routes by content rulesMany rule targetsRouting on event content, SaaS and AWS service events

Writing SQS code means respecting the visibility timeout: receiving a message hides it, and you must finish processing and call delete before the timeout expires, or the message reappears for another consumer — one reason duplicate handling matters. Use long polling (WaitTimeSeconds up to 20) so receive calls wait for messages instead of hammering an empty queue. FIFO queues add strict ordering per MessageGroupId and deduplication via a deduplication ID or content-based deduplication. SNS code publishes with message attributes, and subscribers attach filter policies so each receives only the messages it cares about.

Walk the classic scenario: an order service publishes each new order once to an SNS topic. Three SQS queues subscribe — billing, fulfillment, analytics — each drained by its own consumer with its own dead-letter queue. Billing being down for an hour loses nothing: its queue buffers, its retries are independent, and fulfillment never notices. That is fanout with durability, and it is the exam's favorite decoupling answer.

Event-driven patterns with Amazon EventBridge

Amazon EventBridge implements event-driven patterns with three building blocks: event buses, rules, and targets. An event bus receives events — the default bus carries events from AWS services in your account, custom buses carry your applications' events, and partner buses receive events directly from integrated SaaS providers. Your code publishes with a PutEvents call carrying a source, a detail-type, and a JSON detail payload.

Rules match events against an event pattern and route them to up to five targets each. This is where content filtering lives: patterns can match exact values, prefixes, numeric ranges, the existence or absence of a field, and anything-but exclusions — over any field in the event body. That moves routing logic out of consumer code and into configuration: a rule can send only orders above a threshold to a fraud-review queue while everything else flows to standard processing. Input transformers reshape the event per target, and each target gets its own retry policy and dead-letter queue for delivery failures.

Targets include Lambda functions, SQS queues, SNS topics, Step Functions state machines, Kinesis streams, and API destinations — authenticated HTTP endpoints with built-in rate limiting, the clean way to push events to third-party APIs. EventBridge also runs scheduled rules for cron-style invocation.

Choose EventBridge over SNS when routing depends on the content of the event body (SNS filter policies primarily match message attributes), when you consume events from AWS services or SaaS partners, or when you want schema discovery. Choose SNS for very high fanout throughput and for delivery protocols like SMS and email.

Handling streaming data with Amazon Kinesis

Handling streaming data means processing an ordered, replayable flow of records with low latency, and on this exam that means Amazon Kinesis. A Kinesis data stream is divided into shards, each providing documented capacity: 1 MB or 1,000 records per second of ingest, and 2 MB per second of read throughput shared across consumers. Producers call PutRecord or PutRecords with a partition key; the key is hashed to select the shard, and ordering is guaranteed only within a shard. That makes key choice a design decision: a high-cardinality key spreads load evenly, while everything sharing one key lands on one shard — the classic hot-shard problem. Scale by resharding: splitting hot shards or merging cold ones.

On the consumer side you can poll with the SDK's GetRecords, but real applications use the Kinesis Client Library (KCL), which balances shards across workers and checkpoints progress so a restarted consumer resumes where it left off. A Lambda function can also consume a stream through an event source mapping — the configuration details belong with Lambda development. Because reads are shared, multiple consumer applications compete for a shard's read throughput; enhanced fan-out gives each registered consumer its own dedicated 2 MB per second per shard with push delivery.

Distinguish the streams from delivery. Kinesis differs from SQS in that records are not deleted when read — the stream retains them (24 hours by default, extendable) so multiple applications can replay the same data in order. Amazon Data Firehose, by contrast, is a fully managed delivery service that batches and loads streaming data into destinations such as S3 or OpenSearch Service: choose it when you need data delivered, not custom-processed.

SDK patterns, third-party resilience, unit testing, and Amazon Q Developer

Writing code that interacts with AWS services through the SDKs comes with recurring patterns the exam probes. Pagination: list and query APIs return one page plus a continuation token (such as NextToken); forgetting the token loop is why an application sees only the first page of results. Use the SDK's built-in paginators instead of hand-rolling loops. Waiters poll a resource until it reaches a target state — waiting for a newly created resource to become active — with backoff built in, replacing fragile sleep-and-check code. Error handling: SDK exceptions are typed, so catch specific throttling and service errors and treat them differently from validation failures.

Skill 1.1.13 extends resilience to third-party integrations, where you control neither availability nor rate limits. Wrap every external call in an explicit timeout, retry transient failures with backoff and jitter, and add a circuit breaker: after consecutive failures the circuit opens and calls fail fast (or serve a fallback) instead of tying up threads against a dead dependency; after a cooling period, trial calls test recovery before the circuit closes. Combine this with a queue in front of the integration so requests survive an outage.

Unit testing works best when business logic is separated from handler wiring, with SDK clients injected so tests mock them and never call AWS. AWS SAM helps you exercise code locally: sam local generate-event emits realistic service event JSON, and sam local invoke runs a function against that event in a Lambda-like container.

Amazon Q Developer

Amazon Q Developer is the AWS AI assistant for development — newly in scope. In the IDE, CLI, and console it generates and explains code, suggests unit tests, and scans code for security issues. Know its purpose as a development aid; deep feature questions are unlikely.

Tip. Expect scenario questions that describe a fragile or overloaded architecture and ask for the fix: a downstream outage losing orders points to SQS decoupling, one event needing multiple independent consumers points to SNS or EventBridge fanout, and a multi-step workflow needing per-step error handling points to Step Functions orchestration. Watch for trigger words — decouple, buffer, spiky traffic, fanout, at-least-once, duplicate processing, content-based routing — each maps to a specific service or pattern. API Gateway questions hinge on knowing that mapping templates, request validation, and status-code overrides are REST API features, and resilience questions reward backoff with jitter, idempotent consumers, dead-letter queues, and circuit breakers over naive immediate retries.

Key takeaways
  • Loose coupling with asynchronous messaging is the exam's default answer for resilience, burst absorption, and independent scaling
  • Choreography = services reacting to events via EventBridge or SNS; orchestration = Step Functions centrally coordinating a visible workflow
  • Fanout = one event to many consumers: SNS topic to multiple SQS queues, or an EventBridge rule with multiple targets
  • Retry only transient errors, always with exponential backoff plus jitter — and make consumers idempotent, because at-least-once delivery guarantees duplicates
  • SQS is a pull queue for one consuming app; SNS pushes to many subscribers; EventBridge routes on event content across AWS, custom, and SaaS sources
  • Only API Gateway REST APIs give you mapping templates, request validators, and status-code overrides — HTTP APIs are cheaper but proxy-only
  • Kinesis orders records per shard by partition key and lets multiple consumers replay data — unlike SQS, reading does not delete
  • Guard third-party calls with timeouts, backoff retries, and a circuit breaker that fails fast while the dependency is down

Frequently asked questions

What is the difference between choreography and orchestration in event-driven architecture?

Choreography has no central controller: each service subscribes to events, reacts, and publishes its own events, typically over EventBridge or SNS — maximizing independence but obscuring the end-to-end flow. Orchestration uses a central coordinator, AWS Step Functions on this exam, that owns the workflow state and directs each step with built-in retries, error handling, and compensation. Choose orchestration when you need visibility and per-step control over a multi-step process; choose choreography when services should evolve independently.

When should I use SQS versus SNS versus EventBridge?

Use SQS when one consuming application must reliably process each message — it buffers work, levels load, and retries until the message is deleted. Use SNS when one event must be pushed to several subscribers at once, classically fanning out to multiple SQS queues. Use EventBridge when routing decisions depend on the content of the event body, or when you consume events from AWS services or SaaS partners through rules on an event bus. The patterns combine: SNS-to-SQS fanout is the standard durable broadcast.

What is exponential backoff with jitter and why does AWS recommend it?

Exponential backoff doubles the wait between retry attempts so a struggling service gets breathing room instead of a hammering client. Jitter adds randomness to each wait so many clients do not retry in synchronized waves — without it, a recovering service is hit by every client at the same instant and fails again. The AWS SDKs implement both automatically for throttling and 5xx errors, with configurable retry modes and maximum attempts; your own code should apply the same pattern to business-level and third-party retries.

How do I transform a request or override a status code in API Gateway?

On a REST API with a non-proxy integration, attach a mapping template — written in Velocity Template Language — to the integration request or integration response to reshape the payload in either direction. To override status codes, configure integration responses that match patterns in the backend response and map them to the method response status the client should receive, for example turning a backend error string into a 404. These features require REST APIs; HTTP APIs use proxy integrations and cannot transform payloads at the gateway.

What is a circuit breaker and when do I need one?

A circuit breaker is a resilience pattern that stops calling a failing dependency: after a threshold of consecutive failures the circuit opens, and further calls fail fast or return a fallback instead of waiting on timeouts and exhausting threads. After a cooling-off period, a few trial calls test whether the dependency has recovered before the circuit closes again. You need one around third-party services whose availability and rate limits you do not control, combined with timeouts and backoff retries for transient errors.

Test yourself on this topic
Practice questions with full explanations.
Practice now

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.