Nobody has started this yet — be first.
Business impact
There is no way for a client to discover what tags exist without fetching every single note and decoding tags client-side. A route, GET /tags, has already been wired up in app/main.py and a response schema (TagCount, with tag: str and count: int) already exists in app/schemas.py -- but the function it calls, crud.list_tags, is only a stub that raises NotImplementedError. The project builds and every other endpoint works; only this one path is unfinished. This is exactly the kind of thing a "tag cloud" or a filter dropdown in a real notes UI would call, and right now that dropdown has nothing to build from.
Problem
GET /tags is routed and its response is fully typed, but crud.list_tags is an unimplemented stub that raises NotImplementedError on every call instead of returning data.
Current behavior
GET /tags raises NotImplementedError -- an unhandled error, not a clean HTTP response -- instead of returning a distinct-tags-with-counts list.
Expected behavior
GET /tags returns a JSON array of {"tag": ..., "count": ...} objects, one per distinct tag currently in use across all notes, sorted alphabetically ascending by tag. A tag used by 3 notes has count: 3. A note with no tags contributes no entries.
Steps to reproduce
cd fastapi/notes_api source .venv/bin/activate uvicorn app.main:app --reload & curl -s http://127.0.0.1:8000/tags
Why this matters
Tags are stored as a single delimited string per note (see the "Tags storage" section of the README and Note.tag_list() in app/models.py), not as their own table -- so "distinct tags across all notes" cannot be expressed as a single SQL GROUP BY over a tags column. It has to be computed by decoding each note's tags in Python, which is exactly the kind of "the storage model has a real, documented consequence" trade-off called out in the README.
Suggested approach
Look at crud.note_to_out and Note.tag_list() for how a note's delimited tags column already gets decoded into a clean Python list elsewhere in this codebase -- list_tags needs the same decoding, just aggregated across every row instead of one. db.query(Note).all() (or similar) gets you every note; building the tag -> count mapping and sorting it is plain Python from there. Watch out for the untagged case: Note.tag_list() returns [] when a note has no tags, not [""].
Acceptance criteria
Verification
.venv/bin/pytest practicetickets/test_ticket03_tag_listing_endpoint.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/tag-listing-endpointFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/tag-listing-endpointSubmit 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.