Start learning free

LESSON 132 OF 173 · BACKEND: SPEED

Project: A Fast Product List in C#

Practice

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. Give the number a default, and refuse anything out of range with 400, like this route for reviews does:

app.MapGet("/reviews", (int? count) => {
    count = count ?? 10;
    if (count < 1 || count > 20) {
        return Results.Json(new { error = "count must be between 1 and 20" }, statusCode: 400);
    }
    ...
});

One cache entry per page: a single key like "products" would hand out the first cached page for every page. Each page needs its own cache key, built from everything that decides its content: after and size, as in "products:6:3". The routes that change products already call cache.Clear(), which 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 const int MAX_PAGE_SIZE = 5;. Set size to PAGE_SIZE when the URL has none, and answer 400 when it is below 1 or above 5. Keep the answer in a variable and return it, 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 with +, which turns the numbers into text. Check the size before you make the key, so a refused size never runs a query or fills a cache entry.


STEP 1 OF 10
    Ctrl + Enter to check

    Speed Project in C#

    Keep going with C#1,600+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free