Reviewed-on: TheLab/shopping-list-api#1
Shopping List API
A simple internal API to track shopping list items using SQLite and FastAPI.
Tech Stack
- Python 3.12
- FastAPI
- SQLite
uvfor dependency management and local workflows- Docker for container packaging
- Gitea Actions for CI
Local Development
Prerequisites
uvinstalled: https://docs.astral.sh/uv/- Python 3.12 available locally
Install dependencies
uv sync --dev
Run the server
uv run uvicorn main:app --reload
The API will be available at http://localhost:8000.
Running Tests
uv run pytest
Tests cover:
- Root endpoint
- Product CRUD
- List CRUD
- List items management (add, update, delete, cascade)
Docker
Build the image
docker build -t shopping-list-api:local .
Run the container
docker run --rm -p 8000:8000 -v "$PWD/data:/app/data" -e DB_PATH=/app/data/shopping.db shopping-list-api:local
This stores the SQLite database on the host under ./data/shopping.db.
Database
SQLite database file: shopping.db by default (created automatically on first startup).
Schema:
products(id, name, sku?, created_at)lists(id, name, created_at)list_items(id, list_id, product_id, quantity, added_at; foreign keys with cascade)
API Reference
Root
GET /
Returns a welcome message.
Response:
{ "message": "Shopping List API" }
Products
POST /products
Create a product.
Body:
{ "name": "string", "sku": "optional string" }
GET /products
List all products.
GET /products/{id}
Get a product by ID.
DELETE /products/{id}
Delete a product.
Lists
POST /lists
Create a shopping list.
Body:
{ "name": "string" }
GET /lists
List all lists.
GET /lists/{id}
Get a list with its items (includes product details in items).
DELETE /lists/{id}
Delete a list (cascades to items).
List Items
POST /lists/{list_id}/items
Add a product to a list.
Body:
{ "product_id": 1, "quantity": 2 }
PATCH /lists/{list_id}/items/{item_id}
Update the quantity of an item in a list.
Body:
{ "quantity": 5 }
DELETE /lists/{list_id}/items/{item_id}
Remove an item from a list.
GET /lists/{list_id}/items
List items in a list (includes product name and sku).
Manual Testing
You can use curl or any HTTP client.
Example flow:
# Create products
curl -X POST http://localhost:8000/products -H "Content-Type: application/json" -d '{"name":"Paper Plates","sku":"PP-001"}'
curl -X POST http://localhost:8000/products -H "Content-Type: application/json" -d '{"name":"Bread"}'
# Create a list
curl -X POST http://localhost:8000/lists -H "Content-Type: application/json" -d '{"name":"Picnic List"}'
# Add items to the list (use IDs from previous responses)
curl -X POST http://localhost:8000/lists/1/items -H "Content-Type: application/json" -d '{"product_id":1,"quantity":2}'
curl -X POST http://localhost:8000/lists/1/items -H "Content-Type: application/json" -d '{"product_id":2,"quantity":1}'
# Get list with items
curl http://localhost:8000/lists/1
# Update quantity
curl -X PATCH http://localhost:8000/lists/1/items/1 -H "Content-Type: application/json" -d '{"quantity":5}'
# List items in list
curl http://localhost:8000/lists/1/items
# Delete item
curl -X DELETE http://localhost:8000/lists/1/items/2
# Delete list (cascades)
curl -X DELETE http://localhost:8000/lists/1
CI
The repository includes a Gitea Actions workflow at .gitea/workflows/ci.yml that:
- installs Python 3.12 and
uv - syncs locked dependencies
- runs the test suite
- builds the Docker image
Notes
- This is an internal API; security/auth is not implemented.
- For production use, consider adding stronger validation, structured logging, and a non-SQLite database if concurrency requirements grow.