Personal Catalogue: React, Express & MongoDB — Chapter 6, Exercise 3 ===================================================================== TASK Temporarily remove escapeRegex() from the search route and search for a term containing an unmatched parenthesis, reproducing the SyntaxError crash. Restore escaping and confirm the identical search term now returns a normal response instead. SOLUTION Temporarily strip the escaping: router.get('/search', async (req, res) => { const q = (req.query.q || '').trim(); if (!q) return res.status(400).json({ error: 'q is required' }); const regex = new RegExp(q, 'i'); // escapeRegex(q) removed on purpose const items = await Item.find({ $or: [{ title: regex }, { author: regex }, { artist: regex }, { director: regex }], }).lean(); res.json(items); }); Send a search containing an unmatched opening parenthesis: curl -i "http://localhost:4000/api/items/search?q=Mission%3A%20Impossible%20(" Output (with the bug reproduced): HTTP/1.1 500 Internal Server Error Content-Type: text/html; charset=utf-8 ...
SyntaxError: Invalid regular expression: /Mission: Impossible (/i:
  Unterminated group
  ...
new RegExp() throws synchronously the instant it's constructed -- before Item.find() is ever called, before MongoDB is ever touched. The global error-handling middleware still catches it (this is a genuinely different error type and cause than Exercise 2's CastError, but the same lack of route-specific handling lets it reach the same generic fallback), confirmed by the same server-side console.error(err) log this time showing a real SyntaxError instead of a CastError. Restore escaping: router.get('/search', async (req, res) => { const q = (req.query.q || '').trim(); if (!q) return res.status(400).json({ error: 'q is required' }); const regex = new RegExp(escapeRegex(q), 'i'); const items = await Item.find({ $or: [{ title: regex }, { author: regex }, { artist: regex }, { director: regex }], }).lean(); res.json(items); }); Repeat the identical request: curl -i "http://localhost:4000/api/items/search?q=Mission%3A%20Impossible%20(" Output (fixed): HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 [] A clean, real 200 response with an empty array -- no item in the catalogue actually has that exact text in any searched field, but the request itself no longer crashes to get that answer. escapeRegex() turned the lone "(" into a literal "\(" before it ever reached new RegExp(), so the constructor received valid syntax and treated the parenthesis as a character to search for rather than the start of an unterminated group. WHY THIS WORKS AS AN ANSWER ---------------------------- It reproduces the exact SyntaxError crash the chapter describes with a real request and a real observed error response, distinguishes it clearly from Exercise 2's CastError (a different root cause reaching the same fallback error handler), and shows the identical search term succeeding with a real, correct empty-result response once escaping is restored -- confirming the fix addresses the actual failure rather than just suppressing a symptom.