Updating and Archiving Products
Products API: Updating and Archiving Products
Welcome back! 👋 Now that you can fetch a single product by ID, it’s time to make that product change over time—updating its fields and archiving it when it should no longer be sold.
In this lesson, you’ll focus on the single-product route at src/app/api/products/[id]/route.ts, specifically the PATCH and DELETE handlers. You’ll see how the route validates the path param, safely parses JSON, validates partial updates, and then delegates to the service layer to actually perform the update or archive.
Previously…
In the previous lesson, you implemented GET /api/products/:id, validating the UUID path parameter and distinguishing a 400 invalid ID from a 404 product not found. That same “be precise about outcomes” mindset carries forward here—except now we’re handling writes, so we add body parsing and patch validation too.
Two write operations on a single product
When working with /api/products/:id, we now support two common “write” actions:
- PATCH
/api/products/:id: apply a partial update (only the fields you send change). - DELETE
/api/products/:id: archive the product (this project treats “delete” as an archive operation and returns the updated product).
Just like the GET-by-id endpoint, both routes clearly separate:
- Invalid input (400 validation errors)
- Missing product (404 not found)
- Successful operation (200 with the updated product)
Route file: src/app/api/products/[id]/route.ts
This file defines the dynamic [id] route and implements GET, PATCH, and DELETE. In this lesson we’ll focus on PATCH and DELETE, since they introduce the most new patterns.
Shared setup: imports and route context:
This top portion establishes the shared tools the route uses: response helpers, JSON parsing, service functions, and UUID validation.
parseJsonis a key difference from earlier routes. Instead of callingreq.json()directly (and risking exceptions on malformed JSON), this helper returns a safe result object you can branch on.validateUpdateProductlives in the service file and is designed specifically for PATCH semantics: it accepts partial input and returns only the validated fields.- The
RouteContexttype matches how this project models dynamic params:context.paramsis aPromise, so every handlerawaits it to access{ id }. isUUIDis used consistently across GET/PATCH/DELETE so invalid path params always produce a predictable 400.
