This project puts the module together in the shop's busiest route, GET /products. Earlier lessons made the list ask only for id, name, price and read one keyset page at a time with ?after=. Two things are still missing: clients can't choose the page size, and the list lost its cache when it got pages.
A size with a limit: clients will pick the size with ?size=, but only up to a limit. Without one, a single request for ?size=1000000 reads and sends the whole table, and the pages were for nothing. Read the number with a default, and refuse anything out of range with 400, like this route for reviews does:
app.get("/reviews", (req: Request, res: Response) => {
const count: number = Number(req.query.count || 10);
if (!Number.isInteger(count) || count < 1 || count > 20) {
return res.status(400).json({ error: "count must be between 1 and 20" });
}
...
});
One cache entry per page: a single answer kept in cache.products would be handed out for every page. Each page needs its own cache key, built from everything that decides its content: after and size, as in "6:3". So cache.products becomes an object with one property per page; the starting code has already given it that type, and a ProductPage type for one page's answer. The routes that change products already run delete cache.products;, which now forgets every page at once.
On a fresh shop, these requests, in this order, must get these answers:
GET /products → 200 {"next_after": 3, "products": [{"id": 1, "name": "Mug", "price": 12}, …]}
GET /products?size=5 → 200 {"next_after": 5, "products": [… 5 products, ids 1 to 5 …]}
GET /products?after=6 → 200 {"next_after": null, "products": [{"id": 7, "name": "Stapler", …}, {"id": 8, …}]}
GET /products?after=6 → 200 the same page, from the cache
GET /debug/queries → 200 {"queries": 3}
POST /products {"name": "Cup", "price": 8} → 201 {"id": 9, "name": "Cup", "price": 8}
GET /products?after=6 → 200 {"next_after": 9, "products": [{"id": 7, …}, {"id": 8, …}, {"id": 9, "name": "Cup", "price": 8}]}
GET /products?size=6 → 400 {"error": "size must be between 1 and 5"}
GET /products?size=0 → 400 {"error": "size must be between 1 and 5"}
GET /debug/queries → 200 {"queries": 5}
Your task: add a constant MAX_PAGE_SIZE of type number set to 5. Read size with PAGE_SIZE as the default, and answer 400 when it is not a whole number from 1 to 5. Write the page query the starting code lost again, with LIMIT set to size, keep the answer in a constant of type ProductPage, and cache each page under its own key for CACHE_SECONDS.
Assignment
Follow the Coding Tutorial to add a page size limit to GET /products and give each page its own cache entry.
Hint
Build the key from both after and size, joined with + and a ":" between them. Check the size before you make the key, so a refused size never runs a query or fills a cache entry. Before storing a page, make cache.products an empty object if it is undefined.
Free plan: 30 tutor messages. PRO is unlimited.
