Nobody has started this yet — be first.
Business impact
GET /recipes currently returns every single recipe row, every time, with every ingredient and step nested in -- no limit. That's fine with a handful of seed recipes; it's a real problem the day this product has real content. A recipe site with 50,000 recipes turns every GET /recipes call into a multi-megabyte response with joined ingredient/step data for rows the client will never render. That's slow responses, wasted bandwidth (worse for anyone on mobile data), and unnecessary load on the database and API process for a page that only ever shows the user 20-50 recipes at a time. This is the single highest-leverage change for keeping the API fast as the content library grows, and it's the kind of thing that's cheap to add now and increasingly disruptive to retrofit later (client code that assumed a bare array has to change no matter when this lands).
Problem
GET /recipes (src/routes/recipes.js) accepts ?maxCookingTime=N but has no concept of page or pageSize. It always runs a single prisma.recipe.findMany({ where, include, orderBy }) over the entire matching result set and returns it as a bare JSON array.
Current behavior
GET /recipes?page=1&pageSize=2 returns a bare array containing every matching recipe, not a paginated { data, meta } envelope -- page and pageSize are silently ignored.
Expected behavior
GET /recipes?page=1&pageSize=20 should return a paginated envelope: { "data": [ /* up to pageSize recipes */ ], "meta": { "page": 1, "pageSize": 20, "total": 137, "totalPages": 7 } }. page and pageSize should both be optional with sane defaults (page=1, pageSize=20) when omitted, meta.total must reflect the full count of matching rows (after maxCookingTime filtering, if present) not just the current page's length, and invalid values (page=0, pageSize=-5, non-numeric) should behave like the existing maxCookingTime validation: a 400 with a field-level ValidationError, not a 500 or a silently-ignored param.
Steps to reproduce
cd nodejs/recipe_api npm run dev # or: docker compose up
curl "http://localhost:3001/recipes?page=1&pageSize=2"
Why this matters
This touches the same where/include/orderBy query object as the existing maxCookingTime filter, so it needs to compose with it rather than replace it -- pagination and filtering are independent axes (you can imagine GET /recipes?maxCookingTime=30&page=2&pageSize=10) and the implementation should treat them that way. Getting total right requires either a second prisma.recipe.count({ where }) call using the same where clause as the paginated findMany, or an equivalent way of counting the full filtered set -- get this wrong and total/totalPages silently drift from what maxCookingTime actually filtered.
Suggested approach
Look at how maxCookingTime is parsed and validated in the GET / handler -- that's the pattern to follow for page/pageSize (parse, validate, throw ValidationError on bad input). Prisma's findMany takes skip/take options for pagination; think about how page/pageSize translate into skip/take. For total, look at what other read methods prisma.recipe exposes for counting rows without fetching them.
Acceptance criteria
Verification
npx jest --config practice-tickets/jest.config.js practice-tickets/tests/03-pagination-missing.test.js
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b feat/paginationFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/paginationSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign indocker-entrypoint.shnpx prisma migrate deploydocker compose up --builddocker compose down -vWithout Docker: npm install, copy .env.example to .env and point DATABASE_URL at a local PostgreSQL instance, then npm run prisma:migrate:dev and npm run dev (nodemon, port 3001) or npm start.
The project's own suite (tests/recipes.test.js) runs against a real Postgres test database, not a mock -- create one, copy .env.example to .env.test and point it at that database, then run:
npm test
Work the tickets in practice-tickets/tickets/ (01 through 07); each names one Jest test in practice-tickets/tests/, run against the same real test database via practice-tickets/jest.config.js:
npx jest --config practice-tickets/jest.config.js practice-tickets/tests/01-max-cooking-time-boundary.test.js # a single ticket
./practice-tickets/run.sh # all 7, clean pass/fail summary
Fixing tickets 02 and 04 also turns two tests in the project's own npm test suite green again -- they break as a direct, expected side effect of those bugs touching shared route code the existing suite also exercises. That's expected, not a mistake in the scaffolding.
Level 2
Implement a feature
Extend the system within its own patterns.