Add the workshop seat-reservation endpoint
Node · Node · advanced · greenfield
Adds the seat-reservation endpoint the checkout service calls after payment: it looks up the workshop, rejects unknown ids and full workshops, then increments the seat counter and returns how many seats remain. The increment itself happens in SQL (`seats_taken + 1`) so the counter math runs in the database. Tested by reserving a seeded workshop down to zero seats and confirming the 409 once it filled.
An events platform. Express + a pg Pool (`db`). Popular workshops sell out in seconds with hundreds of concurrent checkout requests for the same row; `workshops(id, capacity, seats_taken)` has no CHECK constraint on the counter.
Requirements
- POST /workshops/:id/reserve claims exactly one seat: respond `201` with `seats_left` (seats remaining after this claim) when a seat was claimed, `409` when the workshop is full, `404` for an unknown id.
- `seats_taken` must NEVER exceed `capacity`, and the number of successful (201) claims for a workshop must never exceed its capacity — even under many concurrent requests. The checkout tier fans out: handlers for the same workshop run concurrently, and every `await` is a point where other requests' queries interleave.
- Reservation records are written downstream by the ticketing service; this endpoint owns only the seat counter. The counter has NO database constraint — the handler alone must uphold the cap under concurrency.
Files touched
- src/routes/reservations.js
--- src/routes/reservations.js
+const express = require('express');
+
+const db = require('../db'); // pg Pool
+
+const router = express.Router();
+
+/**
+ * Claim one seat for a workshop. Called by the checkout service after
+ * payment; reservation records are written downstream by ticketing.
+ */
+router.post('/workshops/:id/reserve', async (req, res) => {
+ const { id } = req.params;
+
+ const { rows } = await db.query(
+ 'SELECT capacity, seats_taken FROM workshops WHERE id = $1',
+ [id],
+ );
+ if (rows.length === 0) {
+ return res.status(404).json({ error: 'Unknown workshop' });
+ }
+
+ const workshop = rows[0];
+ if (workshop.seats_taken >= workshop.capacity) {
+ return res.status(409).json({ error: 'Workshop is full' });
+ }
+
+ await db.query(
+ 'UPDATE workshops SET seats_taken = seats_taken + 1 WHERE id = $1',
+ [id],