Debug Watch List Movie Operations

Read the full interview experience this question came from →

Quick Overview

This question evaluates backend debugging, RESTful API semantics, data validation and integrity, persistence behavior, and correct HTTP status and error-response handling for watch-list movie operations.

Debug Watch List Movie Operations

Company: Amazon

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Online Assessment

You are given a full-stack **Movie DB** application. Users can log in, create, update, and delete watch lists, and add or remove movies from a watch list. Several unit tests are failing around watch-list movie operations. Your job is to debug and fix the backend logic so that all of the listed scenarios behave correctly, with the right persistence and the right HTTP responses. This is a debugging exercise: the data model and routing already exist — focus on correcting the handler logic rather than redesigning the system. The following scenarios must work correctly: 1. Add a movie to an existing watch list. 2. Add a movie that is already present in the watch list. 3. Remove a movie from an existing watch list. 4. Add many movies to a watch list, then remove them one by one. 5. Try to add a movie to a watch list that does not exist. 6. Try to remove a movie from a watch list that does not exist. ### Constraints & Assumptions Assume a conventional REST contract such as: - `POST /watchlists/{watchListId}/movies` adds a movie (the movie identifier comes from the request body). - `DELETE /watchlists/{watchListId}/movies/{movieId}` removes a movie. - `404 Not Found` is returned when the watch list or movie does not exist. - `409 Conflict` is returned when attempting to add a duplicate movie. - `201 Created` or `200 OK` is returned for a successful add. - `200 OK` or `204 No Content` is returned for a successful delete, depending on the existing API convention. Additional working assumptions: - The watch list stores a collection of movie identifiers, and identifiers may be object/reference types rather than plain strings. - The persistence layer is asynchronous (handlers must wait for a save to complete before responding). - Where the contract above leaves a choice (e.g. `201` vs `200`, `200` vs `204`), match whatever the existing passing tests and surrounding code already assume — do not introduce a new convention. ### Clarifying Questions to Ask - Are movie identifiers stored as plain strings or as object/reference IDs, and how should two identifiers be compared for equality? - For a successful add, do the tests expect `201 Created` or `200 OK`, and for a successful delete do they expect `200 OK` or `204 No Content`? - When adding a movie, must the movie itself exist in the database, or is it enough that the identifier is well-formed? - When the watch list exists but the movie is not currently in it, what status should a delete return — `404`, or a no-op success? - Is the persistence layer synchronous or asynchronous, and are partial/in-memory mutations automatically saved? - Should any of these operations be idempotent (e.g. deleting a movie that isn't present), or should they error? --- ### Part 1 — Add a movie (scenarios 1, 2, 5) Make the add handler satisfy scenarios 1, 2, and 5. Decide which conditions must be validated before anything is added, which status each failure maps to under the contract above, and what a successful add returns once the change is durable. Scenarios 2 and 5 in particular should tell you which checks are currently missing or in the wrong place. ```hint Ordering There is more than one thing that can be wrong with the request: the watch list, the movie, and duplication. Settle the order in which you check them *before* you touch the collection, and make sure a failed check ends the handler rather than letting later code run. ``` ```hint Comparing identifiers A duplicate that the test expects to be caught but isn't usually points at *how* you compare identifiers. Re-read the assumption about identifier types and ask whether your equality check would actually treat two "equal" identifiers as equal. ``` ```hint Persistence pitfall Changing the collection in memory and reporting success are two different things. Think about what order of operations is required before the response goes out, and whether your handler can reach more than one response for a single request. ``` #### What This Part Should Cover ```premium-lock What This Part Should Cover ``` ### Part 2 — Remove a movie (scenarios 3, 6) Make the remove handler satisfy scenarios 3 and 6. Work out which validations the remove path shares with the add path and which are unique to it, how a removal becomes durable, and how the handler should respond when the watch list is missing versus when the targeted movie simply isn't in the list (revisit the relevant clarifying question to decide that status). ```hint Removing the right element Make sure the operation targets only the requested identifier and that whatever result the removal produces is actually written back onto the watch list. Two classic bugs hide here: matching on the wrong field, and producing a new collection that never replaces the old one. ``` ```hint Detecting "not present" Removing a movie that isn't there should not look like a successful removal. Find a signal you can read off the operation itself (e.g. did the collection length change?) that tells you whether anything actually changed, and branch on it. ``` #### What This Part Should Cover ```premium-lock What This Part Should Cover ``` ### Part 3 — Sequential add-then-remove integrity (scenario 4) Make the handlers robust enough that adding many movies and then removing them one by one leaves the watch list in the correct state at every step. ```hint What this test really checks This is a state-integrity test layered on top of Parts 1 and 2 rather than a new feature. If each individual add and remove persists correctly and a removal only ever affects the one identifier it targets, the sequence tends to pass on its own. The failures to watch for are operations that overwrite or reset more of the collection than intended. ``` #### What This Part Should Cover ```premium-lock What This Part Should Cover ``` ### What a Strong Answer Covers ```premium-lock What a Strong Answer Covers ``` ### Follow-up Questions - The current logic does a read, then a mutate, then a save. What concurrency problem appears if two requests add to the same watch list simultaneously, and how would you make the add atomic? - How would you make the delete operation idempotent without losing the ability to report a genuinely invalid request, and what would change in the contract? - If a watch list could hold tens of thousands of movies, what would you change about the duplicate-check and removal so they don't degrade to a full scan on every call? - How would you structure the tests or the handlers so a future bug in one path (e.g. a missing `return`) can't silently send two responses?

Overview: This question evaluates backend debugging, RESTful API semantics, data validation and integrity, persistence behavior, and correct HTTP status and error-response handling for watch-list movie operations.

Read the full Amazon Software Engineer interview experience this question came from

Community answers

Answer by sumansaurabh63

Part 1 — Add a Movie (Scenarios 1, 2, 5) To fix the failing unit tests for adding a movie, we must enforce a strict order of validation and ensure object references are compared using their underlying string values rather than memory references. Correct Handler Implementation TypeScript``` async function addMovieToWatchList(req: Request, res: Response) { try { const { watchListId } = req.params; const { movieId } = req.body; // Assuming { "movieId": "..." } // 1. Validate Watch List Existence (Scenario 5) const watchList = await WatchList.findById(watchListId); if (!watchList) { return res.status(404).json({ error: "Watch list not found" }); } // 2. Validate Duplicate Movie (Scenario 2) // Fix: Use .toString() or .equals() for object/reference identifiers const isDuplicate = watchList.movies.some(id => id.toString() === movieId.toString()); if (isDuplicate) { return res.status(409).json({ error: "Movie already exists in this watch list" }); } // Optional: Validate if the movie itself exists in the global DB if required const movieExists = await Movie.exists({ _id: movieId }); if (!movieExists) { return res.status(404).json({ error: "Movie not found" }); } // 3. Mutate and Persist Asynchronously (Scenario 1) watchList.movies.push(movieId); await watchList.save(); // Ensure save completes before responding // Match existing API convention (e.g., 201 Created) return res.status(201).json(watchList); } catch (error) { return res.status(500).json({ error: "Internal server error" })

Answer by andy

POST /watchlists/:watchListId/movies Find the watch list by watchListId. If it does not exist: return 404 Not Found (If required by the application/tests) Find the movie by movieId. If it does not exist: return 404 Not Found Check whether the movie is already in the watch list. Compare IDs correctly (e.g. ObjectId.equals(), or convert both to strings). If already present: return 409 Conflict Add the movie. Await persistence. await watchList.save() Return the success status already used by the project (201 Created or 200 OK).

Answer by abuhurayraniloy02

Debug Watch List Movie Operations --- Suggested Solution Part 1 --- Add a movie Correct order of operations Validate the watch list exists. If not found → 404 Not Found. (If required by the application) Validate the movie exists. If not found → 404 Not Found. Check for duplicates. Compare movie identifiers, not object identity. If already present → 409 Conflict. Add the movie to the watch list. Persist the change. The persistence layer is asynchronous, so **await the save/commit** before responding. Return success. Use 201 Created or 200 OK, whichever the existing project/tests expect. Why compare IDs instead of objects? The prompt states that the watch list may store objects/references rather than plain strings. Example: watchlist.movies = [ Movie(id="123", title="Inception"), Movie(id="456", title="Interstellar") ] Incorrect: if movieId in watchlist.movies: Correct: if any(movie.id == movieId for movie in watchlist.movies): return 409 If the identifier itself is an object (e.g. MongoDB ObjectId), use the framework's equality method (equals()) or convert both sides to the same type before comparing. Part 2 --- Remove a movie Correct order of operations Validate the watch list exists. If not found → 404 Not Found. (If required) Validate the movie exists. If not found → 404 Not Found. Verify the movie is currently in the watch list. If absent, return the status expected by the project (commonly 404, though some APIs choose idempotent 204). Remove the matching movie. Await pers

Answer by Explorer10

Here's how I'd solve this question: First Debugging Watch List Movie Operations in a Full-Stack Movie DB Application Debugging backend APIs is much more than making failing unit tests pass. In real-world software engineering interviews, especially for backend, full-stack, and Node.js roles, interviewers want to understand how you reason through a failing system, identify the root cause, and implement fixes that preserve correctness across multiple scenarios. In this debugging exercise, here the goal is to repair the backend logic responsible for managing movies inside user watch lists. The application already contains the data model, API routes, and persistence layer. Rather than redesigning the architecture, the objective is to identify flaws in the request handlers and ensure every operation follows the expected REST contract. The failing scenarios reveal several common backend mistakes: Missing validation before modifying data Incorrect duplicate detection Improper comparison of object identifiers Forgetting to persist asynchronous updates Returning incorrect HTTP status codes Continuing execution after sending an error response Removing the wrong element from a collection A systematic debugging process is the key to solving all six scenarios. Let's Understand the Expected API Contract The application exposes two REST endpoints for managing watch list movies. POST /watchlists/{watchListId}/movies Adds a movie to an existing watch list. DELETE /watchlists/{watchListId}/movi

Answer by Xiaoming

[Incoming Request] │ ▼ READ ──► Fetch Watch List from DB (Await) │ ▼ VALIDATE ──► Check if Watch List exists? (If no, 404 & RETURN) │ ──► Check if Movie exists in DB? (If required, 404 & RETURN) │ ──► Check Duplicate/Presence? (409 Conflict / 404 Absent) ▼ MUTATE ──► Push or Filter the array in-memory │ ▼ PERSIST ──► Save Watch List to DB (Await) │ ▼ RESPOND ──► Return success status (201 Created / 200 OK / 204 No Content)
|Home/Software Engineering Fundamentals/Amazon
Amazon logo
Amazon
Jun 12, 2026
mediumSoftware EngineerOnline AssessmentSoftware Engineering Fundamentals
974
0

You are given a full-stack Movie DB application. Users can log in, create, update, and delete watch lists, and add or remove movies from a watch list.

Several unit tests are failing around watch-list movie operations. Your job is to debug and fix the backend logic so that all of the listed scenarios behave correctly, with the right persistence and the right HTTP responses. This is a debugging exercise: the data model and routing already exist — focus on correcting the handler logic rather than redesigning the system.

The following scenarios must work correctly:

  1. Add a movie to an existing watch list.
  2. Add a movie that is already present in the watch list.
  3. Remove a movie from an existing watch list.
  4. Add many movies to a watch list, then remove them one by one.
  5. Try to add a movie to a watch list that does not exist.
  6. Try to remove a movie from a watch list that does not exist.

Constraints & Assumptions

Assume a conventional REST contract such as:

  • POST /watchlists/{watchListId}/movies adds a movie (the movie identifier comes from the request body).
  • DELETE /watchlists/{watchListId}/movies/{movieId} removes a movie.
  • 404 Not Found is returned when the watch list or movie does not exist.
  • 409 Conflict is returned when attempting to add a duplicate movie.
  • 201 Created or 200 OK is returned for a successful add.
  • 200 OK or 204 No Content is returned for a successful delete, depending on the existing API convention.

Additional working assumptions:

  • The watch list stores a collection of movie identifiers, and identifiers may be object/reference types rather than plain strings.
  • The persistence layer is asynchronous (handlers must wait for a save to complete before responding).
  • Where the contract above leaves a choice (e.g. 201 vs 200 , 200 vs 204 ), match whatever the existing passing tests and surrounding code already assume — do not introduce a new convention.

Clarifying Questions to Ask Guidance

  • Are movie identifiers stored as plain strings or as object/reference IDs, and how should two identifiers be compared for equality?
  • For a successful add, do the tests expect 201 Created or 200 OK , and for a successful delete do they expect 200 OK or 204 No Content ?
  • When adding a movie, must the movie itself exist in the database, or is it enough that the identifier is well-formed?
  • When the watch list exists but the movie is not currently in it, what status should a delete return — 404 , or a no-op success?
  • Is the persistence layer synchronous or asynchronous, and are partial/in-memory mutations automatically saved?
  • Should any of these operations be idempotent (e.g. deleting a movie that isn't present), or should they error?

Part 1 — Add a movie (scenarios 1, 2, 5)

Make the add handler satisfy scenarios 1, 2, and 5. Decide which conditions must be validated before anything is added, which status each failure maps to under the contract above, and what a successful add returns once the change is durable. Scenarios 2 and 5 in particular should tell you which checks are currently missing or in the wrong place.

What This Part Should Cover Premium

Part 2 — Remove a movie (scenarios 3, 6)

Make the remove handler satisfy scenarios 3 and 6. Work out which validations the remove path shares with the add path and which are unique to it, how a removal becomes durable, and how the handler should respond when the watch list is missing versus when the targeted movie simply isn't in the list (revisit the relevant clarifying question to decide that status).

What This Part Should Cover Premium

Part 3 — Sequential add-then-remove integrity (scenario 4)

Make the handlers robust enough that adding many movies and then removing them one by one leaves the watch list in the correct state at every step.

What This Part Should Cover Premium

What a Strong Answer Covers Premium

Follow-up Questions Guidance

  • The current logic does a read, then a mutate, then a save. What concurrency problem appears if two requests add to the same watch list simultaneously, and how would you make the add atomic?
  • How would you make the delete operation idempotent without losing the ability to report a genuinely invalid request, and what would change in the contract?
  • If a watch list could hold tens of thousands of movies, what would you change about the duplicate-check and removal so they don't degrade to a full scan on every call?
  • How would you structure the tests or the handlers so a future bug in one path (e.g. a missing return ) can't silently send two responses?
Loading comments...