Let the framework route
Express gives you routing, params, query parsing and JSON for free. Its real power is middleware: small functions every request flows through — for request ids, auth, logging — and one error handler at the end so a failure never leaks a stack trace.
app.js
import express from "express";
import { MENU } from "./lib/menu.js";
import { loadSpecials } from "./lib/specials.js";
const app = express();
let nextId = 1;
app.use((req, res, next) => {
res.set("X-Request-Id", String(nextId++));
next();
});
app.get("/api/dishes", (req, res) => {
const page = Number(req.query.page ?? 1);
const limit = Number(req.query.limit ?? 10);
if (!Number.isInteger(page) || page < 1 || !Number.isInteger(limit) || limit < 1) {
return res.status(400).json({ error: "Invalid page" });
}
const all = req.query.veg === "true" ? MENU.filter((d) => d.veg) : MENU;
const items = all.slice((page - 1) * limit, page * limit);
res.json({ items, page, total: all.length });
});
app.get("/api/dishes/:id", (req, res) => {
const dish = MENU.find((d) => d.id === Number(req.params.id));
if (!dish) return res.status(404).json({ error: "Dish not found" });
res.json(dish);
});
app.get("/api/specials", async (req, res, next) => {
try {
res.json(await loadSpecials());
} catch (err) {
next(err);
}
});
app.use((err, req, res, next) => {
console.error(err.message);
res.status(500).json({ error: "Something went wrong" });
});
export default app;