Nobody has started this yet — be first.
Business impact
GET /notes always returns results ordered by id (i.e. creation order), with no way for a client to ask for anything else -- no newest-first, no alphabetical. A sort query parameter has already been added to the route in app/main.py and threaded through to crud.list_notes, but crud.list_notes raises NotImplementedError for any non-None sort value, valid or not. The default (no sort given) path is completely unaffected and still works exactly as before. Any real notes UI -- a "recently updated" view, an alphabetical list -- needs this before it can offer anything beyond raw insertion order.
Problem
crud.list_notes raises NotImplementedError for any non-None sort value passed through from the already-wired-up query parameter in app/main.py, regardless of whether that value is valid or garbage.
Current behavior
GET /notes?sort=title_asc (or any other non-null sort value) raises NotImplementedError instead of returning ordered results, and there is no query-level validation rejecting an unrecognized sort value with a clean 422.
Expected behavior
GET /notes?sort=<value> accepts one of created_at_asc, created_at_desc, title_asc, title_desc and orders the results accordingly. Any other value for sort is rejected with 422 Unprocessable Entity. sort remains fully combinable with the existing q and tag filters.
Steps to reproduce
cd fastapi/notes_api source .venv/bin/activate uvicorn app.main:app --reload & curl -s "http://127.0.0.1:8000/notes?sort=title_asc"
Why this matters
There are two separate pieces here. First, ordering: translating a sort keyword into a SQLAlchemy .order_by() clause on top of the existing filtered query. Second, validation: rejecting an unrecognized sort value as a client error (422), not as a 500 or a silent fallback to default order -- right now sort is typed as a plain str | None in the route signature, so FastAPI has no way to know which values are valid and lets anything through to crud.list_notes. Getting the validation piece "for free" from FastAPI/Pydantic's own request validation, rather than hand-rolling an if/raise inside the endpoint body, is the more idiomatic approach in a codebase that leans on Pydantic models specifically so /docs and validation stay accurate and automatic.
Suggested approach
For the validation half: look at how sort's type is declared in the list_notes route in app/main.py, and how FastAPI/Pydantic can validate a query parameter against a fixed, known set of string values automatically instead of accepting any str. For the ordering half: look at the TODO comment next to the NotImplementedError in crud.list_notes -- you'll need a mapping from each valid sort value to the matching Note column and direction, applied via .order_by() on the existing query before it's executed.
Acceptance criteria
Verification
.venv/bin/pytest practicetickets/test_ticket05_sort_query_param.py -v
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/sort-query-paramFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/sort-query-paramSubmit 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 in./data/notes.dbOr run it via Docker instead:
cd fastapi/notes_api
docker compose up --build # API on http://127.0.0.1:8000, /docs included
SQLite data is written inside the container to /app/data/notes.db, backed by the notes-data named volume declared in docker-compose.yml -- it survives docker compose restart and re-running docker compose up after down (without -v).
Work the tickets in practicetickets/ (ticket01 through ticket07); each names one pytest file in the same directory, separate from the project's own tests/ suite:
.venv/bin/pytest practicetickets/test_ticket01_tag_length_boundary.py -v # a single ticket
./practicetickets/run_tickets.sh # all 7, pass/fail summary
./practicetickets/run_tickets.sh -v # summary + full output
Note: ticket 02's bug also breaks two pre-existing tests in tests/test_notes.py (test_search_by_q_matches_title_and_content_case_insensitively and test_filter_by_tag_and_q_are_combinable) -- that's expected, and fixing ticket 02 should bring tests/ back to fully green. Run the main suite with .venv/bin/pytest tests/ -v.
Level 2
Implement a feature
Extend the system within its own patterns.