You're designing an order-processing feature using managed backend services: AWS Cognito for auth, DynamoDB to store orders, and EventBridge plus SNS to notify a shipping partner when an order is placed. Concretely, how do these three managed services get wired together into a working flow, and what glue code (if any) is still required?
answer
- DynamoDB Streams triggers Lambda
- Cognito scopes IAM, doesn't know about orders
- EventBridge rules route by event pattern
- glue Lambdas still need idempotency
- at-least-once delivery
basics
~20 sCognito checks who the user is, DynamoDB stores the order data, and when a new order is saved, a small event rule automatically tells EventBridge/SNS to notify the shipping partner — no server is running in between.
solid answer
~40 sCognito issues a signed identity token on login; the client attaches it to requests, and API Gateway or the DynamoDB SDK validates it (via a Cognito authorizer or IAM policy) before allowing the write. The order write to DynamoDB is configured with DynamoDB Streams enabled, which emits a change record on every insert; a Lambda function subscribed to that stream reads the new order and publishes a message to an EventBridge bus or SNS topic. EventBridge rules then route that event to the shipping partner's integration (another Lambda, a webhook, or a queue). The 'glue' isn't a full backend — it's a handful of small Lambda functions and IAM policies/event rules — but that glue is real code you own, test, and can get wrong.
go deeper
Should describe the high-level flow — login, then save an order, then something notifies shipping — without necessarily naming the specific AWS mechanisms.
Should name the concrete mechanisms (Cognito JWT/IAM, DynamoDB Streams, Lambda as glue, SNS/EventBridge routing) and understand that glue code is still required and owned by the team.
Should reason about failure modes in the chain — stream consumer retry/head-of-line blocking, missing dead-letter handling, IAM policy scope — and design for idempotency given at-least-once delivery.
Should weigh synchronous-in-request vs event-driven decoupling trade-offs, discuss observability across a multi-service event chain (distributed tracing gaps), and decide when this composed-services approach outgrows its usefulness versus consolidating into a dedicated service.
## What composability means here Composability in a BaaS-based architecture means chaining several vendor-managed primitives so that one service's write or event automatically triggers work in the next, **without a traditional monolithic server sitting in the middle to orchestrate it**. Working through the order-processing example concretely: ## Identity **First, authentication.** Amazon Cognito runs a hosted user pool; when a user logs in, Cognito verifies credentials and returns a JSON Web Token (JWT) containing the user's identity and claims. The client attaches that token to subsequent requests. - If the client writes directly to DynamoDB via the AWS SDK, a **Cognito Identity Pool** exchanges the JWT for temporary AWS credentials scoped by an IAM policy (e.g., 'this user may only `PutItem` into orders where partition key equals their own user ID'). - If instead the client goes through API Gateway, a **Cognito authorizer** validates the JWT on each request before it reaches a Lambda function. Either way, Cognito's job ends at 'who is this and what are they allowed to touch' — it does not know anything about orders. ## Persistence and the event trigger **Second, persistence and the event trigger.** The order write lands in DynamoDB as a single item (e.g., partition key `orderId`, attributes for customer, items, total). **DynamoDB Streams**, an optional feature on the table, captures an ordered, near-real-time log of every insert/update/delete as a change record. This stream is the mechanism that turns a passive database into an active one: instead of some other service having to poll DynamoDB for 'any new orders?', DynamoDB pushes the change out. A Lambda function is configured as a stream consumer — AWS's stream-poller service invokes the Lambda automatically whenever new records appear, batching them for efficiency. ## Notification and integration **Third, the notification/integration layer.** That Lambda function reads the new-order record from the stream event and publishes a structured event (order ID, items, shipping address) to either an SNS topic or an EventBridge event bus. - **SNS** is push-based pub/sub — every subscriber (an SQS queue, another Lambda, an email address, an HTTPS webhook) gets the message immediately. - **EventBridge** is closer to a rules engine: it accepts events tagged with a source and detail-type, and separately configured rules decide which targets each event pattern routes to, which makes it easier to add a fourth or fifth consumer later without touching the code that publishes the event. In this scenario, an EventBridge rule matching 'order placed' events routes them to a target that calls the shipping partner's API — often yet another small Lambda that adapts the internal event shape to the partner's expected webhook payload, handles retries, and logs failures. ## Why the pattern exists Why this pattern exists: it lets each managed service stay narrowly scoped and independently scalable — Cognito scales identity verification, DynamoDB scales storage/throughput, EventBridge/SNS scale fan-out — while the 'glue' Lambdas are small, stateless, and only responsible for translating between one service's shape and the next. This is the composability promise of BaaS/serverless: instead of one monolithic backend owning auth, persistence, and integration logic in one codebase and one deploy, you get a directed graph of managed services connected by thin functions, each independently deployable and observable. ## What the glue still costs you The trade-off is that this composability is not free of code or of failure modes — it just moves them. The glue Lambdas are real code that must be written, tested, versioned, and monitored, and now there are more integration points (Cognito to app, DynamoDB Streams to Lambda, Lambda to EventBridge, EventBridge rule to partner) each of which can silently misconfigure. - A common production failure is a **DynamoDB Streams consumer that falls behind or throws repeatedly**: by default, a failing Lambda stream consumer retries the same batch indefinitely, which can block all newer records behind it (head-of-line blocking) until someone adds a maximum retry count with a destination for failed batches. - Another is an **IAM policy on the Cognito Identity Pool** that's too permissive or too restrictive — too permissive lets users write into each other's data, too restrictive breaks the feature in a way that only shows up for specific access patterns. - And because SNS/EventBridge deliver 'at least once,' the shipping-partner Lambda must be **idempotent** (safe to invoke twice for the same order) or the partner can receive duplicate shipping notifications, a subtle bug that only appears under retries or network blips, not in a straight-line demo. ## Where it shows up A concrete real-world instance of exactly this composition pattern is the standard AWS 'DynamoDB Streams to Lambda to EventBridge/SNS' fan-out used in serverless e-commerce reference architectures, where order, inventory, and shipping are separate bounded contexts kept in sync entirely through this event chain rather than through synchronous service-to-service calls.
- What happens in this order-processing flow if the shipping-partner Lambda triggered by EventBridge throws an error on every invocation for one particular order?EventBridge (and Lambda's built-in retry behavior) will retry the invocation a bounded number of times with backoff, and if a dead-letter queue or EventBridge's own failure destination is configured, the event lands there for manual inspection instead of being silently dropped. If no dead-letter target is configured, the event can simply be lost after retries are exhausted, which is a common production gap teams discover only when a customer reports a missing shipment.
- Why is idempotency important for the Lambda that notifies the shipping partner, specifically because of how SNS/EventBridge deliver messages?SNS and EventBridge guarantee at-least-once delivery, meaning the same event can be delivered more than once during retries or infrastructure blips. If the shipping notification isn't idempotent (e.g., keyed by order ID so a duplicate is a no-op), the partner can end up shipping — or billing — the same order twice.
- Why use DynamoDB Streams plus a Lambda consumer instead of having the order-write API call the shipping notification directly in the same request?Calling the notification synchronously couples the order write's success to the shipping integration's availability and latency — if the partner's endpoint is slow or down, the customer's checkout request fails or hangs. Decoupling via a stream and async consumer lets the order write succeed immediately and the notification retry independently, trading immediate consistency for resilience and looser coupling between bounded contexts.
It's like an airport: Cognito is the passport check that decides who may proceed, DynamoDB is the baggage system that stores each bag, and EventBridge/SNS is the conveyor and paging system that automatically notifies the next handler the moment a bag lands — nobody has to walk over and ask 'any new bags?'
saying these in an interview costs you the question
- Describes a single monolithic server orchestrating all three services with polling instead of event-driven triggers
- Doesn't mention that glue Lambda code still needs to be written, tested, and versioned
- Assumes delivery is exactly-once and doesn't consider duplicate-event/idempotency handling
- Can't explain what DynamoDB Streams or an equivalent change-data-capture mechanism does
- Conflates authentication (Cognito) with authorization for data access (IAM/rules)