Discover how one file can replace dozens and keep your API neat and powerful!
Why Catch-all API routes in NextJS? - Purpose & Use Cases
Imagine building an API where you must create a separate file for every possible URL path your app might receive, like /api/user, /api/user/profile, /api/user/profile/settings, and so on.
Manually creating many files for each URL path is slow, confusing, and hard to maintain. It's easy to make mistakes and miss paths, leading to broken or inconsistent API behavior.
Catch-all API routes let you handle many URL paths with a single file. This means you write one flexible handler that can respond to any nested path, making your code simpler and easier to manage.
pages/api/user.js pages/api/user/profile.js pages/api/user/profile/settings.js
pages/api/[...slug].js // One file handles /user, /user/profile, /user/profile/settings, etc.
It enables building scalable APIs that adapt to many URL patterns without extra files or complex routing logic.
Think of a blog where posts have categories and subcategories. Instead of making a file for each category path, a catch-all route handles all post URLs dynamically.
Manually creating many API files is tedious and error-prone.
Catch-all routes let one file handle many URL paths.
This simplifies API code and makes it easier to scale.
Practice
[...slug].js in Next.js do?Solution
Step 1: Understand catch-all route naming
In Next.js, files named with[...name].jscatch all nested paths under that route.Step 2: Check how parameters are passed
The parts of the URL matched are passed as an array inreq.query.name, hereslug.Final Answer:
It catches all URL paths that match and provides the parts as an array in req.query.slug. -> Option AQuick Check:
Catch-all route = array in req.query [OK]
- Thinking it catches only one path instead of many
- Expecting a string instead of an array in req.query
- Confusing catch-all with optional catch-all routes
Solution
Step 1: Recall catch-all route syntax
Catch-all routes use three dots inside square brackets before the name, like[...slug].js.Step 2: Compare options
Only [...slug].js matches the correct syntax for catch-all routes.Final Answer:
[...slug].js -> Option BQuick Check:
Catch-all filename = [...name].js [OK]
- Using single brackets without dots for catch-all
- Placing dots outside brackets
- Missing brackets entirely
pages/api/[...params].js with this handler:export default function handler(req, res) {
res.json(req.query.params);
}What will be the JSON response for a request to
/api/a/b/c?Solution
Step 1: Understand catch-all parameter passing
The catch-all[...params]captures all path parts as an array inreq.query.params.Step 2: Check the handler response
The handler returnsreq.query.paramsas JSON, so the response is the array of parts.Final Answer:
["a", "b", "c"] -> Option CQuick Check:
Catch-all returns array of path parts [OK]
- Expecting a string instead of an array
- Confusing JSON structure returned
- Not recognizing catch-all returns array
pages/api/[...slug].js but when you request /api (no extra path), you get an error. What is the likely cause?Solution
Step 1: Understand catch-all vs optional catch-all
Catch-all[...slug].jsrequires at least one path part; it does not match the base path alone.Step 2: Identify fix for base path requests
To handle base path/apiwith no extra parts, use optional catch-all[[...slug]].js.Final Answer:
Catch-all routes require at least one path segment; use optional catch-all [[...slug]].js instead. -> Option DQuick Check:
Catch-all needs path parts; optional catch-all handles empty [OK]
- Expecting catch-all to match empty path
- Misnaming the file without brackets
- Ignoring export of handler function
/api/a/b/c it returns {"0": "a", "1": "b", "2": "c"}. Which handler code inside pages/api/[...parts].js achieves this?Solution
Step 1: Understand the input and desired output
The catch-all parameterpartsis an array of path parts. We want to create an object with keys as indices and values as parts.Step 2: Check which code builds the object correctly
export default function handler(req, res) { const obj = {}; req.query.parts.forEach((p, i) => { obj[i] = p; }); res.json(obj); } loops overreq.query.partsand assigns each part to the object with its index as key, then returns it as JSON.Final Answer:
export default function handler(req, res) { const obj = {}; req.query.parts.forEach((p, i) => { obj[i] = p; }); res.json(obj); } -> Option AQuick Check:
Loop parts to object with index keys = export default function handler(req, res) { const obj = {}; req.query.parts.forEach((p, i) => { obj[i] = p; }); res.json(obj); } [OK]
- Returning array or string instead of object
- Not looping to create object keys
- Returning length instead of parts
Ready to prove it?
Pass the test and this pattern moves unknown
