Amazon .NET Developer Interview Questions & Answers

amazon icon

Questions with Detailed ExplanationsWith Detailed Explanations

(Last Updated: August 28, 2026)

21. How do you handle calls between clients and REST API services with increased volumes?API DesignHardAmazon

Question Details

Describe how the API and its callers behave under higher traffic, including the handling of volume increases without changing the contract.

Short Interview Answer (30-60 seconds)

At a high level, I would keep the REST contract stable and scale everything behind it. Clients send HTTPS requests through edge and DDoS protection to an API gateway. The gateway handles AuthN/Z, rate limiting, validation, caching, quotas, and routing. It forwards work to stateless ASP.NET Core services that scale horizontally. Those services use async I/O, Redis, the primary database, and a message broker for background work. This handles larger volumes well, but the trade-off is more infrastructure and operational complexity.

Detailed Explanation

This question asks how I would keep an API working when many more callers start using it. The callers should not need a new contract just because traffic grows. My goal is to protect the service, spread work across more copies, reduce unnecessary database work, and move slow work away from the main request. I also need good visibility when something becomes overloaded or unhealthy. I would explain the design by following the diagram from the clients through the gateway and .NET service, then through data and background-processing paths, and finally back to the callers.

Useful Questions to Ask the Interviewer
  • How large can the traffic increase become?
  • Are short traffic spikes or sustained high traffic more important?
  • Which operations can be processed asynchronously?
  • Must the existing client-facing API contract remain unchanged?
How do you handle calls between clients and REST API services with increased volumes? diagram
How to Explain It in an Interview
1. Protect the incoming client traffic

I would start with the main request path. Web, mobile, and third-party clients send HTTPS API requests. The diagram also shows JWT or mTLS as caller security options. Requests first pass through Edge Protection and DDoS protection. This keeps abusive traffic from consuming application capacity. Valid traffic then continues to the API Gateway. The client-facing contract remains the same even when the system scales internally.

2. Control traffic at the API Gateway

The API Gateway is the main traffic-control point. It handles AuthN/Z, which means authentication and authorization, plus rate limiting, request validation, caching, and quotas. Rate limiting stops one caller from consuming too much capacity. Quotas place broader usage limits on callers. The gateway also works with the Identity Provider through OIDC, OAuth 2.0, and JWKS. Token or key information flows to the gateway, and token validation is performed before protected traffic is accepted. The gateway then forwards the request to the .NET API service.

The diagram also shows separate HTTPS gRPC or REST exchanges between the gateway and Internal Services such as User, Billing, and Inventory services. These are supporting service-to-service paths and are not the client response path.

3. Scale the stateless .NET API horizontally

The receiving service is a stateless ASP.NET Core API running on Kestrel. Stateless means one request does not depend on private server state stored in one specific replica. That allows the service to scale horizontally by adding API Instance 1, Instance 2, through Instance N.

Inside the service, the middleware pipeline handles logging, validation, security, and correlation. Controllers or Minimal APIs receive the request. Validation and mapping can use System.Text.Json as shown in the diagram. Business logic uses task-based asynchronous work, which helps the service wait for I/O without holding a thread for the whole wait. Health checks help identify unhealthy instances.

4. Use the database and distributed cache carefully

The API service performs asynchronous I/O against the Primary Database through its connection pool. The database returns data back to the API service. The service can also perform cache get and set operations against the Distributed Cache, shown as Redis.

Caching reduces repeated database work for frequently requested data. This is useful when traffic increases because the database often becomes a bottleneck before stateless API instances do. The cache is an optimization, while the primary database remains the main persistent data store shown in the design.

5. Offload long-running work asynchronously

I would not keep long-running processing inside the synchronous client request when it can be moved out. The .NET API service can publish work asynchronously to the Message Broker. The diagram shows RabbitMQ, Kafka, SQS, or EventBridge as broker choices.

Background Workers consume the queued work and handle processing, emails, or integrations. Queue buffering provides backpressure when work arrives faster than workers can process it. This protects the API from being overwhelmed and lets worker capacity scale independently.

6. Return responses and keep the system observable

For the synchronous path, the .NET API service sends its response back to the API Gateway. The gateway returns the response through Edge Protection and then to the client over HTTPS.

Cross-cutting concerns support the whole design. The diagram shows telemetry with OpenTelemetry, logging, metrics, health checks, logs, traces, and alerts. It also shows timeouts, retries, a circuit breaker, high availability across multiple availability zones or regions, rate limiting, queue buffering, and load shedding. These controls help the system stay useful under higher volume. The trade-off is more moving parts, higher cost, and more operational work, but callers keep the same API contract while the implementation scales behind it.

Practical Complexity & Trade-offs

The benefit is that the public API contract stays unchanged while capacity grows behind it. Stateless ASP.NET Core instances are easy to add, but shared data must live outside one replica. Rate limiting, quotas, and load shedding protect the service, but some excess traffic may not be served immediately. Redis reduces repeated database work, but caching adds another system to operate. Async I/O improves concurrency, while the message broker and workers move long-running work away from the request path. That improves responsiveness, but queues and workers add complexity. Timeouts, retries, and circuit breakers improve resilience, but retries must be controlled so they do not create even more traffic. Multi-AZ or multi-region deployment improves availability but costs more. Observability adds operational work, but it is essential for finding bottlenecks during high volume.

Why Interviewers Ask This

Interviewers ask this to see whether I can scale an API without breaking its callers. They want clear judgment about traffic protection, gateway responsibilities, stateless horizontal scaling, database pressure, caching, and asynchronous work. They also check whether I understand request and response direction, authentication and authorization, resilience, backpressure, and observability. The important skill is deciding where each responsibility belongs and explaining the trade-offs instead of only naming scaling technologies.

Interviewer may ask next
What would you do if traffic suddenly became ten times higher for a short period?

I would keep the API contract unchanged and use the existing controls to absorb as much of the burst as possible. Edge Protection and DDoS protection would filter abusive traffic first. The API Gateway would continue enforcing AuthN/Z, request validation, rate limiting, quotas, and caching. The stateless ASP.NET Core service could then scale horizontally by adding more healthy API instances.

I would reduce repeated pressure on the Primary Database by using Redis for suitable cached data. Long-running work would continue to move through the Message Broker instead of blocking synchronous requests. Queue buffering creates backpressure when Background Workers cannot keep up immediately. Timeouts, retries, circuit breakers, load shedding, health checks, logs, metrics, traces, and alerts would help prevent or detect cascading problems.

The main downside is that scaling is not unlimited or free. New capacity takes resources, queued work can grow, and dependencies can still become bottlenecks. During an extreme burst, rate limiting, quotas, or load shedding may still protect the overall system by refusing excess work.

How would you handle long-running processing as request volume keeps increasing?

I would keep suitable long-running work outside the synchronous request path. After the request passes the gateway controls and reaches the ASP.NET Core service, the service can publish the longer task asynchronously to the Message Broker. The diagram supports RabbitMQ, Kafka, SQS, or EventBridge for that broker role. Background Workers then consume the work and perform processing, emails, or integrations.

This keeps API instances available for client-facing requests instead of making them wait for slow background tasks. Queue buffering also provides backpressure when work arrives faster than workers can process it. Worker capacity can scale separately from API capacity. Logs, metrics, traces, alerts, and queue signals help operators see whether a backlog is growing.

The main downside is additional operational complexity. The broker and workers must be monitored and kept healthy. Processing is also no longer part of the immediate synchronous response path, so the design must treat the queued work as a separate asynchronous flow while keeping the original client contract unchanged.

22. Design a rate limiter for an API that supports millions of requests per second.API DesignHardAmazon

Question Details

Design a high-throughput API rate limiter and explain how it would enforce limits under very high request volume.

Short Interview Answer (30-60 seconds)

At a high level, I would place a stateless rate limiter before the ASP.NET Core application. Requests pass through Edge/DNS and the global load balancer to a Rate Limiter Gateway. The gateway identifies the caller, resolves its policy, and atomically checks distributed counters. Allowed requests continue to the application and downstream services. Requests over the limit return HTTP 429. I would shard counters by key and horizontally scale limiter instances. The main trade-off is accurate distributed enforcement versus the extra latency and cost of checking shared counters.

Detailed Explanation

The goal is to stop one caller from sending too many requests while still serving millions of requests every second. The check must be fast because every request goes through it. Several machines may receive requests from the same caller, so they must make consistent limit decisions. The diagram solves this with many stateless rate-limiter instances, shared distributed counters, configurable policies, and separate allowed and rejected paths. Requests that pass the check reach the application. Requests that exceed their limit are stopped before they consume application or downstream capacity.

Useful Questions to Ask the Interviewer
  • What should define a limit: API key, user, IP, endpoint, or tenant?
  • How strict must each per-key limit be across replicas?
  • Should the limiter allow short traffic bursts?
  • Do different tenants or API keys need different quotas?
Design a rate limiter for an API that supports millions of requests per second. diagram
How to Explain It in an Interview
1. Start with the request path

I would keep the request path short. A client sends an HTTPS API request through Edge/DNS. The request reaches the global load balancer, which sends it to one of many Rate Limiter Gateway instances. These gateway instances are stateless and horizontally scalable. That means we can add replicas as traffic grows without depending on process-local state for the authoritative decision.

2. Identify the caller and resolve its policy

The Rate Limiter Gateway extracts the identity used for limiting. The diagram supports an API key, JWT, IP address, or user ID. It then resolves the matching rate-limit policy. The Policy & Config Service owns rules such as limits per tenant or key, quotas, windows, burst settings, and dynamic updates. This keeps policy management separate from the fast request-processing path.

3. Check and update the distributed counter

The gateway next checks and updates the High-throughput Distributed Store. Counters are partitioned by key, so unrelated callers can be spread across different shards. Operations for one key are atomic. In simple terms, many concurrent requests cannot all read the same old counter value and incorrectly pass the limit.

The diagram shows atomic operations such as increment, expiry, and scripts. It also supports fixed window, sliding window, token bucket, and leaky bucket policies. Token bucket is useful when controlled bursts are acceptable. The chosen rule comes from the configured policy.

4. Allow or reject the request

If the caller is within its limit, the gateway sends the allowed request to the API Gateway / Application running ASP.NET Core. The application can then make its internal gRPC or HTTP call to Downstream Services. The downstream response returns to the application, and the API response returns through the normal response path toward the client.

If the caller exceeds its limit, the limiter rejects the request with HTTP 429. The rejected request does not continue to the ASP.NET Core application. This protects both the application and its downstream services from excessive traffic.

5. Scale the hot path

I would run many stateless Rate Limiter Gateway instances and auto-scale them. The counter store is sharded by key, with the diagram calling out consistent hashing for distribution. This allows many unrelated counters to be processed in parallel while preserving strong handling for one key.

For performance, the diagram also shows in-memory counters, connection pooling, pipelining, and batching. These reduce overhead, but separate limiter replicas must not treat independent process memory as one shared authoritative counter.

6. Add reliability, security, and observability

The design uses TLS for traffic and mTLS between services where shown. API keys or tokens are validated before they are trusted as caller identity. High availability comes from stateless gateways, health checks, auto-scaling, and multi-AZ or multi-region deployment.

The limiter emits metrics and logs to Observability & Telemetry. Important signals include requests per second, allowed requests, rejected requests, and latency. Distributed tracing, dashboards, alerts, and audit logs help operators find failures and unusual traffic.

7. Finish with the trade-off

The main trade-off is accuracy versus latency and cost. A distributed atomic counter gives a strong per-key decision, but remote counter access adds work to every check. Local memory is faster, but separate replicas do not share the same heap state. I would therefore keep the gateways stateless, shard the authoritative counters by key, and use the shown performance optimizations without weakening the required limit behavior.

Practical Complexity & Trade-offs

The benefit of this design is easy horizontal scaling. Rate Limiter Gateway instances are stateless, so more replicas can be added as request volume grows. Sharding spreads different counter keys across multiple store nodes. Atomic operations keep one key correct when many requests arrive at the same time. The downside is that checking a distributed store adds network work and latency. Local in-memory counters are faster, but separate processes do not share that state and could disagree. Token bucket can allow controlled bursts, while other window algorithms have different accuracy and traffic-shaping behavior. TLS and mTLS protect network communication, while API-key or token validation protects caller identity. Observability adds operational work, but it is needed to understand latency, allowed traffic, rejected traffic, and failures.

Why Interviewers Ask This

Interviewers ask this question to test whether you can protect an API at very high traffic without losing correctness. They want to see knowledge of stateless scaling, distributed counters, sharding, atomic updates, and HTTP 429 behavior. They also evaluate whether you protect downstream services, separate policy management from the hot request path, understand the trade-off between latency and accurate enforcement, and include practical reliability, security, and observability decisions.

Interviewer may ask next
What would you do if one API key suddenly became extremely hot and generated a large share of all traffic?

I would keep the same architecture and focus on protecting the partition that owns that hot key. The affected path is the Rate Limiter Gateway to the High-throughput Distributed Store. Because counters are partitioned by key, one extremely busy key can overload its assigned shard even when other shards still have spare capacity. I would make sure the counter store can scale that workload and use the performance optimizations already shown in the diagram, including connection pooling, pipelining, and batching. An in-memory optimization may reduce some overhead, but I would not let independent gateway replicas become separate authoritative sources for the same key. The distributed atomic counter must still preserve the required per-key decision. Requests that exceed the policy continue to return HTTP 429 before reaching the ASP.NET Core application. The main downside is that a hot key can still concentrate work on one partition, so strict per-key accuracy can limit how freely that single counter is spread across independent nodes.

How would you handle rate-limit policy changes while the system is processing millions of requests per second?

I would keep policy changes separate from the synchronous application request path. The Policy & Config Service remains responsible for limits per tenant or key, quotas, windows, burst settings, and dynamic updates. Rate Limiter Gateway instances use that policy information while continuing to handle requests. A policy change therefore does not move rate-limit ownership into the ASP.NET Core application or change the normal request flow. Each request still passes through Edge/DNS, the global load balancer, and a Rate Limiter Gateway. The limiter still performs its atomic counter check in the distributed store before allowing or rejecting the request. Observability & Telemetry should show the effect of policy changes through allowed counts, rejected counts, request rate, and latency. The main downside is coordination overhead because many stateless limiter replicas need current policy information. The design accepts that operational complexity so policies can change dynamically without putting policy management directly into the business application.

23. Design a solution to filter a list based on criteria. This question is about API design and organizing the code to be flexible and maintainable.API DesignEasyAmazon

Question Details

Design a flexible filtering API, clarify how criteria are composed and applied, and explain the maintainability concern highlighted in the report.

Short Interview Answer (30-60 seconds)

At a high level, I would keep the filtering API simple at the edge and flexible inside the service. The client sends HTTPS to GET /api/products?filter=... or POST /api/products/search. The API Controller validates the request, then the Filter Parser builds a Criteria Tree. The Specification Builder turns that tree into reusable predicates. The Query Executor applies them through EF Core, and the database returns matching rows. The API returns JSON to the client. I would whitelist fields and operators, enforce authentication, authorization, and limits, and accept more internal structure for better maintainability.

Detailed Explanation

The goal is to let a client ask for only the products it needs. For example, it may want electronics within a price range. The main challenge is keeping this flexible without putting every possible filter inside the controller. We also want new filters to be easy to add later. The diagram solves this by breaking filtering into small steps. Each step has one clear job. The request moves through those steps, reaches the database, and then the matching data returns to the client.

Useful Questions to Ask the Interviewer
  • Which product fields should clients be allowed to filter?
  • Which operators do we need, such as equals, greater than, or in?
  • Should we support both the GET filter endpoint and the POST search endpoint?
  • What limits should we place on page size and filter complexity?
Design a solution to filter a list based on criteria. This question is about API design and organizing the code to be flexible and maintainable. diagram
How to Explain It in an Interview
1. Start with the API boundary

I would keep the public API small and move filtering logic behind it. The client uses HTTPS and can call GET /api/products?filter=... or POST /api/products/search, exactly as shown in the diagram. The API Controller accepts the request. It validates input, handles paging and sorting, and later returns the response. The controller should not contain every filter rule. Its main job is to coordinate the request. This keeps the API contract stable while the filtering implementation can grow independently.

2. Parse and validate the filter

The API Controller passes the filter to the Filter Parser. The parser understands the supported filter syntax, such as RSQL, OData, or a custom DSL. A DSL is simply a small language used to describe filters. The diagram shows an RSQL example with category, price, brand, and rating conditions. The parser validates allowed fields and operators before building the internal representation. Field and operator whitelisting is important because clients should not be able to query arbitrary internal properties or unsupported operations.

3. Build a criteria tree

The Filter Parser converts the request into a Criteria Tree, also called an AST. An AST is a structured tree that represents the meaning of the filter. Comparison nodes represent operations such as equals, greater than, less than, or in. Logical nodes combine conditions with AND, OR, and NOT. This gives the application one consistent internal model. It also separates filter syntax from the reusable filtering rules. That makes parsing and filtering easier to test independently.

4. Convert criteria into reusable specifications

Next, the Specification Builder converts the Criteria Tree into specifications. A specification is a reusable predicate that describes which records should match. Specifications can be combined, so category, price, brand, and rating rules do not need one large hard-coded method. The reusable Filter Library supports this design with a Criteria Model, Operators, Field Mapping, Specifications, and Custom Filters. New filters can be added by implementing new specifications or operators without changing the API contract or controller logic. This is the main maintainability benefit shown in the diagram.

5. Execute the database query

The Query Executor, shown as the repository, applies the specifications to an IQueryable. It also applies sorting, paging, and projection before executing the query. EF Core translates the supported query expression into SQL and sends that SQL to the database. The database returns matching rows to the Query Executor. Keeping the query as IQueryable until execution allows supported filtering work to happen in the database instead of first loading the entire product list into application memory.

6. Return the response and apply cross-cutting controls

The matching data returns from the database to the Query Executor and then through the application to the API Controller. The controller returns the JSON response over HTTPS to the client. Several cross-cutting controls support the flow. Authentication and authorization use the JWT or OAuth2-based approach shown in the diagram. Input validation and field or operator whitelisting protect the filtering boundary. Rate limiting and maximum-result protection reduce abuse and overly expensive requests. Logging and monitoring provide operational visibility. Error Handling and Problem Details provide consistent error information. These controls support the request path without replacing the filtering components.

7. Explain the trade-off

The benefit is flexibility. Criteria are modular, reusable, and testable. New filters can be added by extending specifications or operators instead of rewriting controller logic. Translating supported predicates into database queries can also improve performance. The downside is more internal structure. We now have a parser, criteria model, specification layer, field mappings, reusable operators, and query execution behavior to maintain. For a very small API with only one or two fixed filters, this may be more design than necessary. I would accept that cost when filtering requirements are expected to grow.

Practical Complexity & Trade-offs

The benefit is that each part has one clear job. The API Controller handles the HTTP request. The Filter Parser understands filter text. The Criteria Tree represents what the filter means. The Specification Builder creates reusable predicates. The Query Executor applies them through EF Core. This makes new filters easier to add and test. The downside is extra code and more concepts for the team to understand. We also need strong validation because flexible filters can create expensive or unsafe queries. Whitelisting fields and operators reduces that risk. Rate limiting and maximum-result limits protect the service from abuse. Database-side filtering can improve performance, but complex predicates may still produce costly SQL. We accept the extra structure because it keeps growing filter logic out of the controller.

Why Interviewers Ask This

The interviewer is checking whether you can design a clean API without putting all filtering logic in one place. They want clear boundaries between request handling, parsing, criteria composition, reusable specifications, and data access. They also want correct request and response flow, safe validation, authentication, authorization, sensible limits, and clear trade-offs. The important skill is engineering judgment: using enough structure for flexibility and maintainability without making a simple problem unnecessarily complicated.

Interviewer may ask next
What would you change if clients started sending very large or complex filter expressions?

I would keep the same API and filtering architecture, but I would strengthen the limits around the Filter Parser and Query Executor. The Filter Parser should continue rejecting unsupported fields and operators. I would also enforce reasonable filter-complexity limits together with the rate limiting and maximum-result protection already shown in the diagram. Paging should remain part of the request handling for large result sets. The Query Executor would still apply specifications, sorting, paging, and projection to the IQueryable, and EF Core would translate supported expressions into SQL. Logging and monitoring would help identify filters that repeatedly create expensive database work. Correctness stays the same because accepted filters still become the same Criteria Tree and specifications. Authentication and authorization also remain unchanged. The main downside is that some otherwise valid filters may be rejected because they are too expensive. That reduces flexibility, but it protects database capacity and keeps one client from harming other users.

How would you add a new filter operator without making the controller harder to maintain?

I would add the operator inside the reusable Filter Library instead of putting new condition logic in the API Controller. The existing request path stays the same. The Filter Parser first needs to recognize the new operator and verify that it is allowed. The Criteria Model then represents it as the appropriate comparison node. The Specification Builder maps that node to a reusable predicate. If the operator applies only to certain fields, Field Mapping and validation rules should enforce that restriction. The Query Executor remains unchanged because it receives the resulting specification and applies it to the IQueryable like the existing rules. The public GET /api/products?filter=... or POST /api/products/search contract does not need to change unless the documented filter syntax itself changes. The main downside is more parser, validation, and test coverage. That extra work is useful because the extension stays isolated instead of spreading conditional logic through the controller and repository.

24. Design a book borrow APIAPI DesignEasyAmazon

Question Details

Design the API surface for borrowing books, including how requests create a borrow action and how responses should reflect availability or rejection.

Short Interview Answer (30-60 seconds)

At a high level, I would expose POST /v1/borrows to create a borrow action when a book is available. The client sends a bearer JWT and JSON request through the API Gateway. The gateway handles TLS termination, rate limiting, JWT authentication, request validation, and routing. The Borrow API Service checks availability and borrowing rules, then uses the data layer to update SQL safely. Success returns 201 Created or 200 OK. Invalid input returns 400, unavailable state returns 409, and invalid authentication returns 401. The trade-off is faster reads and notifications with more operational complexity.

Detailed Explanation

The goal is to let a person borrow a book through an application. The system must check that the request is valid and that the book can still be borrowed. It must save the new borrow and update the available inventory. The response should clearly tell the person whether the action worked or why it was rejected. The main challenge is keeping availability correct when several people try to borrow at the same time. The diagram shows the complete request, storage, response, security, cache, and notification flow.

Useful Questions to Ask the Interviewer
  • Can a user borrow only one physical copy of a book at a time?
  • What maximum borrow period, renewal limits, and due-date rules should apply?
  • Should 201 Created be the normal success response, with 200 OK used only for selected successful cases?
Design a book borrow API diagram
How to Explain It in an Interview
1. Start with the API contract

I would start with POST /v1/borrows because this operation creates a borrow record. The client is a web or mobile application. It sends the request over HTTPS with Authorization: Bearer <JWT> and Content-Type: application/json. The JSON body contains userId, bookId, and dueDate. The diagram example uses user-123, book-456, and 2025-06-15. These values identify the borrower, the requested book, and the requested return date.

2. Send the request through the API Gateway

The HTTPS request first reaches the API Gateway. The gateway terminates TLS, performs rate limiting, authenticates the JWT, validates the request, and routes it. JWT authentication checks whether the caller presents a valid token. The gateway then forwards the authenticated request to the Borrow API Service over HTTPS. The diagram includes 401 among the possible client responses, so missing or invalid authentication can be rejected before the borrow operation continues.

3. Validate the borrow inside the service

The Borrow API Service owns the borrowing workflow. It validates the request, checks book availability, creates the borrow transaction, updates book inventory, publishes domain events, and returns the result. The book must be available and not already borrowed. The service also applies the shown borrow policy, including maximum borrow period, renewal limits, and due-date rules. Security also includes role-based access and input validation. For example, a due date in the past is invalid and produces 400 Bad Request with an InvalidRequest error.

4. Read and update stored data

The service uses the Data Access Layer for persistence work. The diagram shows Entity Framework Core, an ADO.NET provider, and connection pooling inside this layer. It reads and writes the SQL Database, which contains Users, Books, Borrows, and Reservations. The data path also reads and writes the book-availability cache, such as Redis. The cache makes availability reads faster, but the durable borrow and inventory state belongs in SQL. This separation keeps the main stored state reliable while still allowing faster availability access.

5. Prevent double booking

The important correctness rule is concurrency control. Two requests may arrive almost together for the final available copy. A simple read followed by an unprotected write could let both requests succeed. The diagram therefore uses row versioning or an atomic update to prevent double booking. Only one request should successfully change the inventory state. The other request observes the conflict and can return 409 Conflict. This keeps the borrow record and available inventory consistent under concurrent requests.

6. Return clear success and rejection responses

The Borrow API Service returns its JSON result back through the API Gateway. The gateway then sends the HTTPS response to the client. A new borrow can return 201 Created with borrowId, userId, bookId, borrowDate, dueDate, and status. The diagram also shows 200 OK as an alternative success response containing borrowId, status, and dueDate. When the book is unavailable, the API returns 409 Conflict with BookNotAvailable, a message, and retryAfter. Invalid input returns 400 Bad Request. Authentication failure can return 401.

7. Publish notifications asynchronously

After the borrow is created, the Borrow API Service publishes a domain event asynchronously to the Message Broker. The diagram gives RabbitMQ and Azure Service Bus as examples. The broker sends the event to the Notification Service. That service sends email or push notifications, such as confirmations or reminders. This work does not need to block the main API response. The benefit is a faster client-facing request. The downside is extra infrastructure and asynchronous processing that must be operated separately.

Practical Complexity & Trade-offs

The API itself is small, but a few design choices matter. POST /v1/borrows clearly represents creating a borrow record. JWT authentication, role-based access, rate limiting, and input validation protect the operation. The 400, 401, and 409 responses tell the client why a request failed. A cache can make book-availability reads faster, but cached information may become stale. The SQL update therefore still needs concurrency control. Row versioning or an atomic update prevents two users from borrowing the same final copy. The message broker moves email and push notifications outside the main response path. The benefit is faster requests. The downside is more moving parts, including a cache and broker, which increase consistency and operational work.

Why Interviewers Ask This

Interviewers use this question to check whether a candidate can turn a simple business action into a clear API contract. They look for correct HTTP behavior, request validation, authentication, authorization, and useful error responses. They also want sound judgment around book availability, concurrent requests, caching, persistence, and asynchronous notifications. A strong answer shows clear ownership between components and explains the trade-offs without adding unnecessary complexity.

Interviewer may ask next
How would you prevent two users from borrowing the last available copy at the same time?

I would keep the same POST /v1/borrows flow and make the final inventory change concurrency-safe. The affected parts are the Borrow API Service, Data Access Layer, SQL Database, and availability cache. Two requests may both read that one copy appears available. The service must not treat that earlier read as the final decision. During the database update, the data layer should use the row-versioning or atomic-update approach shown in the diagram. Only one request should successfully change the available inventory and create the valid borrow. The other request detects that the state has changed and returns 409 Conflict with the BookNotAvailable response. The availability cache should then reflect the current state. JWT authentication, validation, borrowing rules, and the normal response path remain unchanged. The downside is extra database conflict handling, but it prevents an incorrect double booking.

How would you send borrow confirmations without making POST /v1/borrows slower?

I would keep notifications asynchronous, as shown in the diagram. The Borrow API Service first completes the borrow work and produces the normal API result. It then publishes a domain event to the Message Broker, such as RabbitMQ or Azure Service Bus. The Notification Service receives that event and sends the email or push notification separately. The client therefore does not wait for notification delivery before receiving the borrow response. The POST /v1/borrows endpoint, gateway checks, database update, cache behavior, and success or rejection responses stay unchanged. Correctness is maintained because the notification does not decide whether the borrow succeeds. It happens after the borrow workflow produces its result. The main downside is extra asynchronous infrastructure and delayed delivery. A notification can arrive after the API response, so the system accepts that timing difference in exchange for a faster request path.

25. Design an API that would take and organize order events from a web store.API DesignEasyAmazon

Question Details

Design an endpoint or small API surface for ingesting order events from a web store and describe how the events are organized after intake.

Short Interview Answer (30-60 seconds)

At a high level, I would use one ASP.NET Core ingestion API to receive order events and process them asynchronously. The web store sends POST /v1/events over HTTPS with a Bearer JWT and an idempotency key. The gateway applies transport and request controls. The controller authenticates, validates, deduplicates, and assigns an EventId. The raw event is retained, then the publisher sends it through a durable message broker. A background processor organizes the data for operations, analytics, and search. The trade-off is better reliability and scaling at the cost of more infrastructure.

Detailed Explanation

The goal is to collect order changes from a web store and keep them useful after they arrive. An order can be created and then change many times. We need a simple way for the store to send each change. We should avoid treating the same event twice when a request is retried. We also should not make the web request wait for every later processing step. The diagram solves this by accepting an event, checking it, retaining it, sending it through reliable messaging, and organizing the result in different stores.

Useful Questions to Ask the Interviewer
  • How many order events should the system handle during peak traffic?
  • Do events for the same order need to stay in order?
  • How long should raw order events be retained?
Design an API that would take and organize order events from a web store. diagram
How to Explain It in an Interview
1. Start with the API boundary

I would start with one clear ingestion endpoint. The Web Store sends POST /v1/events over HTTPS. The request is JSON. The API surface shows Authorization: Bearer <JWT>, Idempotency-Key: <guid>, and Content-Type: application/json.

The request first reaches the API Gateway. The gateway terminates TLS, applies rate limiting, checks the IP allowlist, limits request size, and performs request validation. The diagram also shows TLS 1.2 or later and secrets stored in Key Vault as security concerns.

2. Authenticate, validate, and deduplicate

The request then reaches the Events Controller inside the ASP.NET Core ingestion service. The controller authenticates the JWT and validates the event schema. Authentication means checking that the caller has a valid identity.

The controller also performs an idempotency check. Idempotency means a retry should not create another independent event. Redis is the Idempotency Store. The diagram says it deduplicates using the Idempotency-Key or EventId. The controller assigns an EventId for a new event.

The success response is 202 Accepted with the EventId. This means intake succeeded and later asynchronous work can continue after the HTTP request finishes.

3. Retain the raw event

The next step is Persist Raw Event. The diagram shows the raw event as immutable and keyed by EventId. It is retained for auditing and reprocessing.

The Organized Storage area contains an Event Store (Immutable Log). It contains raw order events in append-only, time-ordered form. This gives the system a history that can be inspected or replayed without changing the original records.

4. Publish through durable messaging

After the persistence step, the publisher sends the event to the Message Broker. The diagram labels this component Ernst Publisher. Its shown responsibilities are publishing to the broker, serializing with System.Text.Json, publishing asynchronously, and acknowledging success.

The Message Broker is shown as Azure Service Bus or RabbitMQ. It provides a durable queue or topic, at-least-once delivery, and partitioning for scale. At-least-once delivery means an event can occasionally be delivered more than once. That is why idempotent handling remains important.

5. Process and organize the event

The Event Processor is a background service. It consumes events, deserializes them, applies business rules, enriches or transforms data, and persists results to storage.

The Operational Store uses Azure SQL Database. It organizes data such as orders, order-status history, customers, and products. The Analytics Store uses Azure Data Lake or Blob storage for raw JSON files, reporting, and analytics. The Search Index uses Azure Cognitive Search for fast lookup by values such as orderId and customerId. The Event Store keeps the immutable event history.

6. Handle failures and observe the system

The diagram shows failed messages moving to a Dead Letter Queue after maximum retries. The DLQ holds poison messages for inspection and reprocessing instead of retrying them forever.

The reliability controls include retries with backoff, an outbound circuit breaker, and idempotency. Observability includes structured logging, Prometheus metrics, and distributed tracing. Monitoring tracks queue depth, failure rate, and latency.

7. Explain scaling and the trade-off

The ASP.NET Core API is shown as stateless and able to scale horizontally. Autoscale rules can add instances when load increases. The durable broker separates incoming traffic from background processing.

The benefit is better resilience and easier scaling during traffic spikes. The downside is more operational complexity. We now operate Redis, a message broker, background processing, several data stores, monitoring, retries, and DLQ recovery. For an order-event system, that extra complexity is reasonable because durable asynchronous processing is valuable.

Practical Complexity & Trade-offs

The benefit is that the HTTP API performs only the intake work before returning 202 Accepted. The message broker then separates the web request from slower background processing. This helps during traffic spikes because events can wait safely in the durable queue. Idempotency reduces duplicate processing when requests or broker deliveries repeat. Keeping immutable raw events also helps auditing and reprocessing. The downside is extra operational work. The design needs a gateway, Redis, a broker, a background processor, and several storage systems. At-least-once delivery can produce duplicate deliveries, so processing must remain idempotent. Rate limiting and request-size limits protect the API. Retries with backoff help temporary failures, while the DLQ isolates messages that continue failing.

Why Interviewers Ask This

Interviewers ask this question to test API and distributed-system judgment rather than memorization. They want to see a clear endpoint, correct request and response behavior, validation, authentication, idempotency, and sensible event organization. They also look for understanding of asynchronous processing, durable messaging, retries, dead-letter handling, observability, and scaling. A strong candidate should explain which component owns each responsibility and clearly describe the trade-off between a simpler synchronous design and this more reliable event-driven design.

Interviewer may ask next
What would you change if order-event traffic became much higher?

I would keep the same POST /v1/events contract and scale the existing components instead of changing the API. The ASP.NET Core ingestion service is shown as stateless, so more API instances can be added behind the existing gateway. The gateway still applies TLS termination, rate limiting, IP allowlisting, request-size limits, and request validation. Redis continues supporting the idempotency check so retries do not become new independent events.

The Message Broker is especially useful during a spike because it buffers events between intake and processing. I would scale broker capacity and add Event Processor instances as queue depth grows. The diagram already monitors queue depth, failure rate, and latency, so those signals can guide autoscaling.

Correctness stays the same because EventId and idempotency controls still apply, while repeated processing failures still use the retry and DLQ path. The main downside is cost. More API instances, broker capacity, workers, and storage throughput all require additional resources.

How would you handle duplicate events and events that keep failing?

I would use the idempotency and dead-letter mechanisms already shown in the design. When the Web Store calls POST /v1/events, it provides an Idempotency-Key. The Events Controller checks the Redis Idempotency Store using the idempotency key or EventId. This prevents a normal retry from being treated as another independent event.

Duplicate protection is also important after publishing because the Message Broker provides at-least-once delivery. That delivery model can send the same event more than once, so downstream work should remain idempotent.

For repeated failures, the diagram uses retries with backoff. After the maximum retries, the failed message goes to the Dead Letter Queue. Operators can inspect and reprocess those poison messages later. The immutable event history also supports auditing and reprocessing.

The downside is extra state and operational effort. Redis entries must be managed, failed messages need investigation, and any reprocessing path must continue respecting idempotency so recovery does not create duplicate results.

26. How would you go about designing an API using AWS API GatewayAPI DesignMediumAmazon

Question Details

Shape the API around AWS API Gateway, including request routing, integration boundaries, and how the gateway sits in front of the backend.

Short Interview Answer (30-60 seconds)

At a high level, I would use Amazon API Gateway as the public front door for the API. Web, mobile, and third-party clients send HTTPS JSON requests with a JWT. API Gateway routes requests such as GET /orders, POST /orders, and GET /customers/{id}. It also handles authentication, request validation, throttling, quotas, caching, and mapping. The request then reaches an AWS backend such as a .NET Lambda function, which performs business logic and accesses the data layer. The response returns through API Gateway. The benefit is centralized API control, while the trade-off is extra gateway and integration configuration.

Detailed Explanation

This question asks how I would put one safe front door in front of several backend services. Clients should not need to know where each backend runs. They should call one API, and that API should decide where each request goes. It should also check important rules before allowing the request through. The backend then performs the real work and accesses stored data. Finally, the result comes back through the same public API. I would explain the design in the same order shown in the diagram.

Useful Questions to Ask the Interviewer
  • Which clients will use the API: web, mobile, third-party applications, or all three?
  • Which routes should use Lambda, ECS/Fargate, Step Functions, or another integration?
  • Which routes need authentication, throttling, caching, or private backend connectivity?
How would you go about designing an API using AWS API Gateway diagram
How to Explain It in an Interview
1. Make API Gateway the public API boundary

I would start by making Amazon API Gateway the client-facing entry point. The diagram shows web, mobile, and third-party applications calling it over HTTPS. The request carries JSON and a JWT.

The production stage uses a custom domain with TLS. Clients therefore call one stable API address instead of connecting directly to individual backend services.

The visible routes are GET /orders, POST /orders, and GET /customers/{id}. API Gateway owns request routing. It decides which configured integration should receive each accepted request.

2. Apply gateway controls before forwarding the request

API Gateway applies common API controls before the backend executes business logic. The diagram shows authentication using Cognito, JWT, or IAM. Authentication means checking who the caller is.

The gateway also performs request validation. This checks whether the incoming request has the expected structure. Throttling and quotas control how much traffic callers can send. Caching can reduce repeated backend work when appropriate. Request and response mapping can transform data for an integration when needed.

If authentication or request validation fails, the request should not continue to the backend. The diagram does not show specific failure status codes, so I would not invent them.

3. Cross the integration boundary into the backend

After the gateway accepts the request, it forwards the request through an AWS integration. The main request arrow is labeled HTTP / AWS Integration.

The backend-services area shows three possible targets: AWS Lambda functions, Amazon ECS / Fargate running a .NET Core Web API, and AWS Step Functions for workflows. The main numbered flow specifically shows API Gateway invoking the .NET Lambda integration.

The backend owns business logic. API Gateway should handle gateway concerns, while application rules stay inside the backend service.

The diagram also shows VPC Link together with private subnets and security groups as a private-integration option. This can be used when a backend must stay private rather than being directly reachable from clients.

4. Keep data access behind the backend

After receiving a valid request, the backend can read or write application data. The data layer contains Amazon DynamoDB, Amazon RDS, and Amazon S3.

DynamoDB represents NoSQL data. RDS represents transactional relational data. S3 represents object storage. The backend owns these data operations. Clients do not directly access these stores through the public request path.

The diagram shows a read or write operation moving from the backend-services side toward the data layer. It also shows the result returning from the data layer toward the backend.

5. Return the result through API Gateway

After the backend finishes its work, it returns a backend response toward Amazon API Gateway. The gateway can apply response mapping if the integration needs it.

API Gateway then sends an HTTPS JSON response back to the original client. This keeps the public response path consistent with the request path. The backend does not bypass API Gateway when replying to the caller.

6. Add identity, protection, and observability around the flow

The security area shows Amazon Cognito, AWS IAM, and AWS WAF. Cognito can provide user identity. IAM provides AWS roles and policies. WAF adds protection against unwanted web traffic patterns.

The observability area shows Amazon CloudWatch, AWS X-Ray, and API Gateway access logs. CloudWatch provides logs, metrics, and alarms. X-Ray provides tracing. Access logs record activity at API Gateway. These tools observe the request flow. They do not own the business response.

7. Explain developer operations and the trade-off

The diagram also includes OpenAPI or Swagger documentation, usage plans and API keys, AWS SAM or CDK, and CodePipeline or GitHub deployment and versioning. These tools help teams describe, deploy, and operate the API consistently.

The benefit is central control over routing, authentication, validation, traffic limits, and monitoring. Backend services can focus on business logic and data access. The downside is more configuration. Teams must understand gateway routes, integrations, identity settings, deployment stages, and private connectivity when they use it.

Practical Complexity & Trade-offs

The benefit is that API Gateway gives all clients one controlled entry point. Routing, authentication, validation, throttling, quotas, caching, and mapping can happen before a request reaches the backend. This keeps common API concerns in one place. The .NET backend can focus on business logic and data access. CloudWatch, X-Ray, and access logs make the system easier to observe. The downside is extra configuration. Teams must manage routes, integrations, identity settings, and deployments. Lambda is useful for function-based work. ECS/Fargate fits a .NET Web API that runs as a service. The diagram also shows VPC Link and private networking for private backends. That improves isolation, but it adds networking and operational work.

Why Interviewers Ask This

Interviewers ask this question to test API design judgment, not AWS service memorization. They want to see whether you can create a clear public boundary and explain who owns routing, authentication, validation, business logic, data access, and responses. They also look for correct request and response direction, sensible backend integrations, security ownership, observability, traffic controls, private connectivity, and clear trade-off communication.

Interviewer may ask next
What would you change if the .NET backend must stay private?

I would keep Amazon API Gateway as the public entry point and use the private-integration option shown in the diagram. The affected area is the integration boundary between API Gateway and the private backend. The backend would stay in private networking protected by private subnets and security groups, while clients would continue to call only API Gateway.

The public API behavior would stay the same. Clients would still send HTTPS requests with JSON and a JWT. API Gateway would still perform routing, authentication, validation, throttling, quotas, and any configured mapping before forwarding an accepted request.

The private backend would still own business logic and data access. Its response would still return through API Gateway to the original client. CloudWatch, X-Ray, and access logs would remain available for observability.

The main downside is operational complexity. VPC Link and private networking require additional configuration and troubleshooting. We accept that cost when keeping the backend private is more important than using the simplest possible integration.

How would you protect and operate this API as traffic grows?

I would keep the same API design and use the gateway controls already shown. API Gateway would continue to own throttling and quotas, which limit how much traffic callers can send. Caching can reduce repeated backend work for routes where cached responses are appropriate. Authentication through Cognito, JWT, or IAM would continue to check caller identity, while AWS WAF would add protection against unwanted web traffic patterns.

I would also use the existing observability components. CloudWatch provides logs, metrics, and alarms. AWS X-Ray helps trace requests. API Gateway access logs show activity at the public boundary. These signals help determine whether a problem is in the gateway, backend integration, application logic, or data layer.

The routes GET /orders, POST /orders, and GET /customers/{id} would stay unchanged. Their responses would still return through API Gateway. The main downside is tuning. Limits that are too strict can block legitimate bursts, while caching adds configuration and is not appropriate for every operation.

27. Design a system and API that should support 50 instances of custom designed Queue. Basically the question is about how you'll make use the given block of memory, to achieve the above requirement.API DesignHardAmazon

Question Details

Explain the queue-management API and the memory-block constraint together, including how multiple queue instances share the same underlying storage.

Short Interview Answer (30-60 seconds)

At a high level, I would expose a queue API while keeping all 50 queues inside one fixed memory block. Clients send HTTPS JSON requests to the ASP.NET Core API Gateway, which forwards valid calls to the .NET 8 Queue Manager Service. A routing layer maps each queue ID to its memory region, while metadata tracks offset, capacity, head, tail, and count. Each queue uses a circular buffer and per-queue locking. The response returns through the gateway. The trade-off is predictable, fast memory use versus fixed capacity and stricter memory management.

Detailed Explanation

The question asks us to support 50 separate queues while using one limited block of memory. We should not create an unrelated memory area for every queue. Instead, the queues share the available block in a controlled way. The API must let clients create queues, inspect them, add messages, remove messages, clear queues, and delete them. The main challenge is keeping every queue separate and safe while sharing the same storage. The diagram solves this with queue regions, small metadata records, circular buffers, and per-queue concurrency control.

Useful Questions to Ask the Interviewer
  • Is the total memory-block size fixed before the service starts?
  • Should all 50 queues have equal capacity, or may capacities differ?
  • Are messages fixed-size, or may they use a length prefix?
  • Must queue configuration survive a process restart?
Design a system and API that should support 50 instances of custom designed Queue. Basically the question is about how you'll make use the given block of memory, to achieve the above requirement. diagram
How to Explain It in an Interview
1. Define the API boundary

I would start with the public API. Web apps, mobile apps, and services send HTTPS JSON requests to the ASP.NET Core API Gateway.

The diagram shows POST /queues, GET /queues, GET /queues/{id}, DELETE /queues/{id}, POST /queues/{id}/enqueue, POST /queues/{id}/dequeue, GET /queues/{id}/size, GET /queues/{id}/stats, and POST /queues/{id}/clear.

The gateway forwards the API call to the Queue Manager Service. The service response returns to the gateway, and the gateway returns JSON to the client.

2. Authenticate and validate the request

The Queue Manager Service first performs Authentication & Authorization using JWT or an API key. Authentication checks who the caller is. Authorization checks whether that caller may perform the requested operation.

Request Validation & Rate Limiting then checks the request before shared memory is changed. Rate limiting protects the service from excessive calls.

3. Route the queue to its memory region

The Queue Routing Layer maps a queue ID to its assigned region inside the shared memory block.

The Queue Metadata Store keeps queueId, startOffset, capacity, head, tail, count, and status. startOffset tells the service where the queue begins. head points to the next item to remove. tail points to where the next item is added. count tracks the current number of messages.

4. Share one fixed memory block

The core design is the Shared Memory Block. The diagram shows one fixed-size block in one process heap or a memory-mapped region.

The block contains 50 queue regions, from Queue 0 through Queue 49. Each queue uses a circular buffer. When the tail reaches the end of its region, it wraps back to the beginning if space is available.

The sum of the queue regions must fit inside the given block. Messages may use fixed-size slots or variable-size storage with a length prefix, as shown in the assumptions.

5. Perform queue operations safely

For POST /queues/{id}/enqueue, the service writes at the tail when that queue is not full. For POST /queues/{id}/dequeue, it reads from the head when the queue is not empty.

GET /queues/{id}/size returns the current size. GET /queues/{id}/stats returns queue statistics. POST /queues/{id}/clear clears a queue. DELETE /queues/{id} removes it and makes its region reusable. GET /queues/{id} returns queue information, while GET /queues lists queues.

The diagram uses a per-queue Lock or SpinLock. This keeps concurrent operations from corrupting that queue's head, tail, count, or message slots. Enqueue and dequeue should not be described as naturally idempotent unless a separate deduplication contract exists, because repeating either operation can change queue state again.

6. Explain operations and trade-offs

Logging, Metrics, and optional Persistence are supporting paths. Logging may use Serilog, files, or ELK. Metrics may use Prometheus. Optional persistence can store queue configuration and limits in PostgreSQL, with EF Core as the data-access layer shown in the diagram.

Circular-buffer enqueue and dequeue are O(1) per queue. The main benefit is predictable memory usage and cache-friendly storage. The downside is that each queue is limited by its assigned capacity, so unused space in one region cannot automatically help another queue without changing the memory-layout policy.

Why Interviewers Ask This

The interviewer is testing whether I can combine API design with careful memory management. They want clear API boundaries, correct request and response flow, safe handling of shared state, and a sensible fixed-memory layout. They also want to see whether I understand circular buffers, queue metadata, concurrency control, validation, authentication, and capacity limits. The key skill is explaining why the design is fast and predictable while also describing its real limitations.

Interviewer may ask next
What happens if one queue becomes full while other queue regions still have free space?

With the design shown, I would respect the capacity assigned to that queue. The affected endpoint is POST /queues/{id}/enqueue. The Queue Routing Layer finds the queue's region, and the Queue Metadata Store provides its capacity, head, tail, and count. If the count has reached that queue's capacity, the Queue Manager Service must not write beyond the region because that could overwrite another queue's memory. The enqueue therefore fails without changing the queue state. Authentication, validation, per-queue locking, logging, metrics, and the normal response path stay unchanged. If the interviewer wants queues to borrow unused space from each other, I would change the memory-layout policy rather than silently crossing region boundaries. That could use a shared pool or movable regions, but it would make allocation and synchronization more complicated. The current fixed-region approach wastes some memory when usage is uneven, but it gives simple addressing, predictable limits, and strong separation between queues.

How do you keep concurrent enqueue and dequeue operations safe across all 50 queues?

I would use the per-queue concurrency control shown in the diagram. The affected path is the Queue Manager Service updating the Queue Metadata Store and that queue's circular-buffer region. Before changing the head, tail, count, or message slots, the service takes that queue's Lock or SpinLock. The protected update must complete as one consistent operation before another conflicting operation changes the same queue state. Requests for different queues can still run independently, so activity on Queue 7 does not unnecessarily block Queue 42. Authentication, authorization, validation, routing, logging, metrics, and all API routes remain unchanged. This prevents lost updates, duplicate removal caused by races, and corrupted head or tail pointers. The main downside is contention when many callers use the same queue at once. A SpinLock can also waste CPU if held too long, so a normal lock is usually safer for longer critical sections. The benefit is fine-grained synchronization without one global lock for all queues.

28. How would you design Amazon.com's database (customers, orders, products, etc)?System DesignMediumAmazon

Question Details

Design the core data model and storage layout for Amazon.com's customer, order, and product data, including the main entities and relationships.

Short Interview Answer (30-60 seconds)

At a high level, the goal is to store Amazon customer, product, order, payment, seller, and inventory data safely while keeping common reads fast. The main challenge is that each data type has different consistency and access needs. I would divide the design into core databases, fast read models, and background event processing. Aurora PostgreSQL stores strongly consistent business data. DynamoDB handles inventory and several read models. Redis and OpenSearch speed reads. The trade-off is more operational complexity and slightly delayed read-model updates.

Detailed Explanation

The system must keep many kinds of shopping data organized and reliable. Customers, products, orders, payments, sellers, and inventory do not all behave the same way. Orders and payments need careful updates, while search and common lookups need fast reads. Inventory also changes frequently. The diagram solves this by separating the official business data from read models built for speed. .NET services own the business actions, while background processing moves slower work away from the main request path.

Useful Questions to Ask the Interviewer
  1. Which records must always show the newest value immediately?
  2. How fresh must inventory availability be?
  3. How quickly should product search reflect catalog changes?
  4. Which data must remain available across Availability Zones?
How would you design Amazon.com's database (customers, orders, products, etc)? diagram
How to Explain It in an Interview
1. Start with clear data ownership

I would give each main business area a clear source-of-truth database. Customers DB uses Aurora PostgreSQL. It stores the customer as the root record, plus addresses, payment methods, and preferences.

Products DB also uses Aurora PostgreSQL. It stores products, categories, brands, prices, and attributes. The diagram also makes the relationship clear that an OrderItem refers to a Product.

Orders DB stores orders, order items, shipping addresses, and totals. An Order belongs to a Customer. An Order contains OrderItems. Each OrderItem points to a Product. Aurora PostgreSQL gives these records ACID transactions and strong consistency.

2. Separate payments, sellers, and inventory

Payments DB stores transactions, payment methods, status, and refunds. Sellers DB stores seller, storefront, payout, and performance data. Both use Aurora PostgreSQL with strong consistency.

Inventory is different. Inventory DB uses DynamoDB. It stores SKU, warehouse, quantity, and reserved quantity. The diagram chooses it for high write volume. Inventory accepts eventual consistency, which means a read may briefly show an older value.

3. Build fast read paths

The main databases keep the official records. Read models are separate copies shaped for common queries.

Product Read Model uses OpenSearch for full-text search, facets, and suggestions. Customer Read Model uses DynamoDB for customer profiles and preferences. Order Read Model uses DynamoDB for history, status, and tracking. Inventory Read Model uses DynamoDB for stock levels and availability.

Redis is the Distributed Cache. It stores sessions, tokens, hot catalog data, and common lookups. These layers improve speed without replacing the source-of-truth databases.

4. Put .NET services around the data

Requests enter through the WAF, where rate limiting is shown. The application layer contains Identity, Customer, Catalog, Order, Payment, Inventory, and Notification services. Shared Libraries contain contracts, DTOs, validation, and policies. The diagram uses ASP.NET Core, Minimal APIs, and gRPC inside the .NET application layer.

Background .NET hosted services include Outbox Publisher, Email/SMS Sender, Search Indexer, and Analytics Processor. The architecture also shows external Payment Gateway, Shipping or Carrier APIs, Tax Calculation Service, and Email or SMS Providers as supporting integrations.

5. Move slower work to events

The Outbox Pattern is kept per service database. It publishes transactional changes into the Event Bus / Stream using Amazon MSK or Kafka.

Inventory Updater, Search Indexer, Notification Dispatcher, and Analytics Aggregator process those events in the background. Analytics writes into the Amazon Redshift Data Warehouse for reporting, BI, and dashboards.

The services are stateless and can scale horizontally. The diagram also calls for partitioned and replicated data, backups across Availability Zones, authentication, authorization, observability, secrets management, disaster recovery, and data governance. The main trade-off is that this design scales different workloads independently, but operating several stores and background flows is more complex.

Engineering Considerations / Design Trade-offs

The benefit is that each workload gets storage that fits its job. Aurora PostgreSQL gives strong consistency for customers, products, orders, payments, and sellers. DynamoDB fits inventory and read models that need to handle large amounts of traffic. Redis and OpenSearch make common reads faster. Background events keep search, notifications, inventory updates, and analytics away from the main request path. The downside is complexity. The team must operate several databases, read models, caches, and event consumers. Some read models can also be slightly behind the main database because their updates happen after the original change.

Why Interviewers Ask This

Interviewers ask this to see whether you can divide a large data problem into clear ownership boundaries. They want to see how you choose relational and NoSQL storage, model important relationships, separate official data from fast read copies, and move background work out of the main path. They also want to hear whether you can explain consistency, scaling, and trade-offs in simple language.

Interviewer may ask next
What would you change if product search traffic became much larger than order traffic?

I would keep the same basic design and scale the search side independently. Products DB would still be the source of truth for products, categories, brands, prices, and attributes. I would not move that ownership into OpenSearch.

Product Read Model would continue using OpenSearch for full-text search, facets, and suggestions. Search Indexer would keep that read model updated through the background processing path. The Distributed Cache could also absorb more hot catalog lookups.

This keeps heavy search traffic away from Products DB. It also lets the search infrastructure grow without forcing Orders DB, Payments DB, or the order services to grow at the same rate.

Correctness is kept because product changes are still written to the main product database first. The read model remains a derived copy. The downside is that search may briefly show older product information while the background update is still being processed.

What would you change if inventory updates became much more frequent across many warehouses?

I would keep Inventory DB on DynamoDB and scale that part of the architecture independently. The existing model already stores SKU, warehouse, quantity, and reserved quantity, which fits frequent inventory changes.

Inventory Service would continue owning inventory behavior. Inventory DB would remain the source of truth for that data. The Inventory Read Model would still serve stock levels and availability. Inventory Updater would process inventory-related events in the background.

The .NET services are stateless, so more service replicas can be added as load grows. The diagram also allows the data layer to be partitioned and replicated across Availability Zones.

Correctness comes from keeping one clear inventory source of truth instead of letting the read model become the main record. The downside is freshness. Because the diagram accepts eventual consistency for inventory, a read model can briefly show an older stock value after a recent update.

29. Design a parking payment system.System DesignEasyAmazon

Question Details

Design the parking-payment flow, including how parking sessions start, how payment is triggered, and what the system should do if a payment step fails.

Short Interview Answer (30-60 seconds)

At a high level, this system lets a driver start a parking session, calculate the charge, pay safely, and finish the session. The main challenge is keeping payment state correct when a gateway call fails or times out. I would explain it in three flows: session handling, payment processing, and background recovery. The .NET services keep the Relational DB as the source of truth, use cache for speed, and use workers for retries and notifications. The trade-off is extra complexity for safer payments.

Detailed Explanation

The system must let a driver start parking, track the session, calculate the amount due, make a payment, and finish the session correctly. The difficult part is handling payment problems. A payment request can fail, be declined, or time out without a clear result. We must avoid charging the driver twice or losing a valid payment. The diagram handles this by separating the normal request path from background work that checks uncertain results, retries safe operations, sends notifications, and records operational information.

Useful Questions to Ask the Interviewer
  1. Can sessions start from the Mobile App, Parking Kiosk, Web Portal, and Entry/Exit License Plate Recognition system?
  2. Should drivers be able to extend an active parking session?
  3. Which payment methods must the Payment Gateway support?
  4. What should happen when a gateway timeout leaves the payment result unknown?
Design a parking payment system. diagram
How to Explain It in an Interview
1. Explain how the request enters the system

I would start with the client request. A driver can use the Mobile App, Parking Kiosk, Web Portal, or Entry/Exit License Plate Recognition system.

The request reaches the API Gateway over HTTPS. The edge layer handles TLS 1.3, rate limiting, authentication and authorization, and input validation. A validated request is then forwarded to the .NET Web API services.

2. Explain sessions, pricing, and stored data

The Session Service manages the parking session. It can start or end a session, calculate charges, and return session status. The Pricing Service provides tariffs, discounts, and promotions used when calculating the amount due.

The services read and write sessions, users, payments, and tariffs in the Relational DB. This database is the source of truth. The Distributed Cache stores session state, pricing data, tokens, and idempotency keys for faster access. An idempotency key lets the system recognize the same payment request when it is sent again.

Blob Storage holds receipts, images, and audit logs.

3. Explain the payment path

When payment is triggered, the Payment Service creates and manages the payment. It calls the Payment Gateway over HTTPS and receives a success or failure result.

The Payment Service can confirm, capture, refund, or void a payment. The integration layer applies timeout, retry, circuit-breaker, and bulkhead policies around external calls. A circuit breaker temporarily stops repeated calls when a dependency is failing. A bulkhead limits how much work one failing dependency can consume.

The service saves the payment result in the Relational DB. The normal response then returns through the API Gateway to the client.

4. Explain background work and failure recovery

Important actions publish events to the Message Bus. Background Workers running as .NET Hosted Services consume those events.

The Session Timeout Worker finds expired sessions, calculates amounts due, and triggers unpaid flows. The Payment Reconciliation Worker checks uncertain payment results with the gateway, marks them successful or failed, and handles chargebacks. The Notification Worker sends receipts, reminders, and payment-failure alerts through the SMS or Email Provider.

A transient failure can be retried with exponential backoff. A declined payment is reported to the user so another method can be tried. A gateway timeout is marked pending and checked later by the Payment Reconciliation Worker. Idempotency keys help prevent duplicate charges during retries.

5. Explain scale, security, and operations

The API services are stateless, so more replicas can run behind a load balancer. The database keeps official state, while the cache improves performance. Payment data is protected with PCI DSS controls, and communication uses TLS.

Structured logs, metrics, traces, and alerts provide observability. The Message Bus and background workers keep slower recovery work away from the main request path. The main trade-off is additional infrastructure and operational complexity in exchange for safer payment handling and better recovery.

Engineering Considerations / Design Trade-offs

The benefit is that the system separates normal user requests from slower recovery work. The Relational DB keeps the official session and payment state, while the Distributed Cache makes common access faster. Idempotency keys reduce duplicate charges when the same request is retried. Background workers can check uncertain gateway results without blocking the main request. The downside is more complexity. We must operate the Message Bus, cache, workers, retry rules, and observability tools. A payment may also remain pending for a short time after a timeout. We accept this because guessing a payment result could create a duplicate charge or lose a valid payment.

Why Interviewers Ask This

Interviewers use this question to see whether you can break a real payment problem into clear flows. They want to know if you understand where official data should live, how retries can cause duplicate payments, and why background workers help with uncertain failures. They also want to hear how you think about security, scaling, monitoring, and practical trade-offs instead of only naming technologies.

Interviewer may ask next
What would you change if the Payment Gateway often times out and does not immediately tell us whether a charge succeeded?

I would keep the same design, but I would depend more on the Payment Reconciliation Worker for payments with an unknown result. When the Payment Gateway times out, the Payment Service should not immediately mark the payment as failed. It should save the payment as pending in the Relational DB.

The payment request should keep the same idempotency key when it is retried. This lets the system recognize the same operation and helps prevent a second charge.

An important payment event goes through the Message Bus. The Payment Reconciliation Worker can then check the Payment Gateway later. If the gateway confirms success, the worker marks the payment successful. If the gateway confirms failure, it marks the payment failed. The Notification Worker can then send the appropriate receipt or payment-failure alert.

The main downside is that the driver may not know the final result immediately. We accept that delay because treating an unknown payment as success or failure without checking could create a payment mistake.

How would this design handle a large increase in parking requests during a major event?

I would keep the same architecture and add more stateless .NET Web API service replicas behind the load balancer. Because the replicas do not depend on local session ownership, requests can be spread across them.

The Distributed Cache helps reduce repeated access for session state and pricing data. The Relational DB still keeps the official state. I would not move payment correctness into the cache just to make requests faster.

Background work can scale separately. More .NET Hosted Service workers can consume events from the Message Bus for session timeouts, payment reconciliation, and notifications. This prevents slower background tasks from blocking the main request path.

Rate limiting at the API Gateway protects the system during sudden bursts or abuse. Structured logs, metrics, traces, and alerts help operators see where delays are building.

The main downside is higher infrastructure cost and more operational work because additional replicas and workers must be monitored and managed.

30. Design an electronic voting system.System DesignEasyAmazon

Question Details

Design the voting workflow with eligibility, vote submission, and result integrity, and explain the trust and failure assumptions the question implies.

Short Interview Answer (30-60 seconds)

At a high level, the system must let an eligible voter submit one valid vote and protect that vote from tampering. The main challenge is keeping vote writes correct while publishing trustworthy results without slowing the voter path. I would explain three flows: eligibility checks, vote submission, and background tallying. The .NET services use strongly consistent vote writes, an outbox, a message broker, encrypted storage, and secure keys. Public results may appear slightly later because tallying runs in the background.

Detailed Explanation

The goal is to let an eligible person vote once, keep that vote private, and produce results people can trust. The difficult part is protecting correctness even when networks or services fail. A vote must not be lost, silently changed, or counted twice. The diagram separates this problem into the voter request path, secure vote storage, background tallying, and public result viewing. It also keeps audit evidence so the final result can be checked later. The design favors vote integrity over the lowest possible write latency.

Useful Questions to Ask the Interviewer
  1. How is voter eligibility defined, and can it change during an election?
  2. How quickly must public results reflect newly accepted votes?
  3. What audit evidence must election officials or outside observers receive?
Design an electronic voting system. diagram
How to Explain It in an Interview
1. Start with security, identity, and eligibility

I would first make sure only an allowed voter reaches the voting logic. The voter uses the Web / Mobile App over HTTPS. The request passes WAF / DDoS Protection and the API Gateway, which applies rate limiting.

Authentication uses MFA / OIDC to confirm identity. Authorization checks the allowed policy or role. The Eligibility Service then performs the voter registry check. Only a validated request continues into the .NET 8 / .NET 10 Application Layer.

2. Submit the vote through the .NET application

For the vote path, the Stateless Web API receives the validated request. Domain Services contain the Ballot Service, Vote Service, Election Service, and Audit Service. The Vote Service handles vote submission while the other services provide election, ballot, and audit responsibilities shown in the diagram.

Cross-Cutting logic handles input validation, idempotency, logging, metrics, tracing, and correlation IDs. Idempotency means the same request can be recognized instead of creating an unintended duplicate action.

Infrastructure Adapters use EF Core for data access and the Distributed Cache for selected lookups. The Primary Database stores users, elections, ballots, encrypted votes, and audit logs. Vote writes favor strong consistency because correctness is more important than the smallest possible write delay.

3. Protect the stored vote and create reliable events

The design encrypts traffic with TLS and protects stored data with encryption at rest. The Key Management Service, shown as KMS / HSM, manages encryption keys and key rotation. Object Storage keeps encrypted audit exports and cryptographic proofs.

The Outbox Table is inside the Primary Database. It records events that need background processing. The Outbox Publisher then publishes those events so the main vote transaction and later background work do not depend on finishing at exactly the same moment.

4. Tally and publish results in the background

I would keep tallying away from the synchronous vote response. Published events go to the Message Broker, shown as RabbitMQ / Azure Service Bus. Background .NET services then perform the later work.

The Tally Processor performs the verifiable tally. The Result Publisher updates the read model. The Audit Exporter produces proofs and logs. Cleanup Tasks are also shown as background work.

This means public results can be eventually consistent, which means they may be a little behind the latest accepted vote. The accepted vote remains the important durable record.

5. Serve results, handle failures, and keep the system observable

For result queries, the design can use the Read Replica and Distributed Cache instead of sending every read to the Primary Database. The Public Results Viewer exposes read-only results over HTTPS. This helps the system scale result traffic without weakening the vote write path.

The design assumes the network is unreliable and services may fail. Stateless services, read replicas, and caches help with scale and availability. It does not promise perfect availability or instant public results.

Operations use Centralized Logging, Metrics, Tracing, Alerts, Dashboards, and Audit & Forensics. The diagram shows ELK / OpenSearch, Prometheus, OpenTelemetry, Alertmanager, Grafana, and immutable audit logs. Trust is anchored in secure KMS / HSM keys, tamper-evident audit records, cryptographic proofs, and transparent result verification.

Engineering Considerations / Design Trade-offs

The benefit is that the most important path stays focused on vote correctness. Strong database writes protect accepted votes, while tallying and result publishing happen in the background. This can make vote submission safer during temporary worker or broker problems. The downside is that public results may be slightly behind the latest vote. Read replicas and caches make result reads easier to scale, but they add more moving parts. Encryption, KMS / HSM keys, audit exports, proofs, and monitoring improve trust, but they also increase operating work and system complexity.

Why Interviewers Ask This

Interviewers use this question to test system-design judgment, not memorization. They want to see whether you can protect eligibility, vote integrity, privacy, and one-person-one-valid-vote behavior. They also look for good choices around durable background work, result freshness, read scaling, failure assumptions, encryption, auditing, and verifiable results. A strong answer explains why correctness is more important than simply making every operation fast.

Interviewer may ask next
What would you change if public results had to update almost immediately after each accepted vote?

I would keep the same vote submission path because vote correctness is still more important than result speed. I would mainly reduce delay in the existing background path.

The Outbox Publisher would publish new events quickly after the Primary Database commit. I would scale the Message Broker consumers and the Tally Processor so pending tally work is processed faster. The Result Publisher would then update the read model sooner. The Read Replica and Distributed Cache could serve those fresher results to the Public Results Viewer.

I would not move tallying into the synchronous vote submission request. That would make a voter depend on the broker, tally worker, and result publishing path before receiving a response. A failure in any of those components could then block voting.

Correctness still comes from protecting the vote write first. The main downside is higher resource use and more operating pressure. Results become fresher, but the design should still avoid promising perfectly instant updates.

What happens if the Message Broker or Tally Processor is unavailable for a while?

I would keep the accepted vote separate from the background failure. The Primary Database remains the important vote store, so a temporary tallying problem should not erase a vote that was already committed correctly.

The Outbox Table keeps the event that still needs to be published. If the Message Broker is unavailable, the Outbox Publisher can continue once that dependency recovers. If the Tally Processor is unavailable, tallying and result publication pause until background processing becomes healthy again.

During that time, public results can be behind the latest accepted votes. That matches the diagram's assumption that background tallying gives eventual consistency for public results. Logging, Prometheus metrics, OpenTelemetry tracing, Alertmanager alerts, Grafana dashboards, and Audit & Forensics help operators detect and investigate the problem.

The main downside is delayed result visibility. The design accepts that delay because protecting the accepted vote is more important than keeping the public result perfectly current.

More questions load as you scroll

Disclaimer: This interview guide is for educational and informational purposes only. It is designed to help readers prepare, but it does not guarantee any interview result, hiring decision, offer, or outcome. Interview questions, hiring criteria, and preferred answers can vary by employer, interviewer, industry, location, and time. The examples and explanations reflect the authors' research and judgment, are provided without warranties of any kind, and should not be treated as the only correct approach. Diagrams are simplified illustrations intended to highlight the main components and their interactions; actual systems and implementations may be more complex. Alternative approaches may be equally valid or better suited to a particular question, context, or interviewer. To the fullest extent permitted by applicable law, the author, contributors, and publisher are not liable for decisions made, actions taken, or losses incurred based on this guide.

Company Notice: This guide is an independent educational resource and is not affiliated with, endorsed by, sponsored by, or approved by the company named in this guide. Company names are used only to identify interview experiences commonly reported by candidates. Interview practices can change without notice, and inclusion of company-specific content does not mean these questions are official, complete, or guaranteed to be asked. To the fullest extent permitted by law, the author, contributors, and publisher are not responsible for outcomes related to use of this material.