Minimal Meeting Room Reservation API
POST /rooms/{room_id}/reservations
Body: { "start": "2024-06-01T10:00:00Z",
"end": "2024-06-01T11:00:00Z" }
Responses:
201 Created → { "reservation_id": "...", "status": "confirmed" }
409 Conflict → { "error": "room already booked for that interval" }
Preventing Overlapping Bookings
Use a database transaction with a lock, not application-level checks:
BEGIN;
SELECT * FROM reservations
WHERE room_id = :room AND start < :end AND end > :start
FOR UPDATE; -- locks matching rows (and gaps via predicate locks
-- in SERIALIZABLE mode)
INSERT INTO reservations (room_id, start, end, user_id)
VALUES (:room, :start, :end, :user);
COMMIT;
How this handles two simultaneous requests:
- Atomicity: Check-and-insert happens in one transaction; a request can't be validated against stale data.
- Locking: With isolation level
SERIALIZABLE (or FOR UPDATE), the second transaction's overlapping check blocks or the insert fails at commit time, so only one transaction succeeds.
- Single winner: The loser gets a rollback and returns
409 Conflict; the client may retry with a different time.
Alternative: enforce uniqueness via a constraint on booked 15-minute slots (inserting one row per slot, unique index on (room_id, slot)), turning races into simple duplicate-key errors.