What2Cook — lightweight recipe finder: give it the ingredients you have and it will suggest recipes. Built with FastAPI, async SQLAlchemy, Postgres, Jinja2 templates and a small, responsive frontend.
- API: FastAPI (OpenAPI docs available at
/docs). - Frontend: Server-side rendered pages (Jinja2) + small JS for search, likes/bookmarks and copy link.
- DB: PostgreSQL (tested with Postgres 17) using asyncpg and SQLAlchemy 2.x (async).
- Auth model: anonymous users tracked by a signed cookie (
anon_id). Likes and bookmarks are stored in the DB but associated with that anonymous user; bookmarks can be fetched and cleared by the same browser cookie. - Packaging: Poetry + pyproject.
- Containerized: Dockerfile +
docker-compose.yml+docker-compose.override.ymlfor local dev (hot reload).
- Search recipes by ingredients (several endpoints:
search,search_simple). - Mapping user free-text ingredient inputs to canonical DB ingredient names (fuzzy/ILike fallback).
- Bookmark and Like actions for anon users (stored server-side + cookie to identify the user).
- Small responsive UI: index carousel, catalog, search, bookmarks, recipe detail.
- Fixtures loader to populate example recipes & ingredients (fixtures/recipes_fixtures.py).
- Alembic migrations included (
alembic/versions/ca3137948eb4_initial.py).
- Python 3.14
- FastAPI
- SQLAlchemy (async)
- asyncpg
- PostgreSQL 17
- Alembic
- Jinja2 templates + Bootstrap 5
- Poetry for dependency management
- Docker + docker-compose for local/dev deployment
1. Copy .env.example to .env and update values
cp .env.example .env
# Edit .env to set a secure SECRET_KEY and (optionally) SPOONACULAR_API_KEY2. Build & run
docker compose up --build -d
# follow logs
docker compose logs -f web3. Create / migrate DB (inside container)
# open a shell in web container
docker compose exec web alembic upgrade head4. (Optional) Load fixtures
docker compose exec -e PYTHONPATH=/app web python fixtures/recipes_fixtures.py5. Open
- Web UI:
http://localhost:8000/ - API docs (Swagger UI):
http://localhost:8000/docs
Dev override
docker-compose.override.yml enables hot reload for the web service (uses uvicorn --reload).
- Install with Poetry:
poetry install --no-dev
# or with dev deps
poetry install- Set
DATABASE_URLin env (see.env.example) and run migrations:
alembic upgrade head- Run dev server:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000From project root (Docker):
# start
docker compose up --build -d
# show logs
docker compose logs -f web
# stop
docker compose down
# restart web only
docker compose restart webAlembic and DB helpers (examples from NOTES.md):
docker compose exec web alembic revision --autogenerate -m "init"
docker compose exec web alembic upgrade head
# drop and recreate public schema
docker compose exec db bash -lc 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"'Load fixtures:
docker compose exec -e PYTHONPATH=/app web python fixtures/recipes_fixtures.pyGET /api/recipes/— paginated list of recipes (used by frontend list/catalog).GET /api/recipes/{id}— get single recipe (detailed JSON).GET /api/recipes/{id}/actions— returnsliked,bookmarked,likes_countfor current anon user.POST /api/recipes/{id}/like— toggle like for current anon user.POST /api/recipes/{id}/bookmark— toggle bookmark.POST /api/recipes/clear— clear anon data (deletes anon user + actions). RequiresX-Requested-With: XMLHttpRequestheader.GET /api/recipes/ingredients?q=...— list ingredient names (prefix filter).GET /api/recipes/search_simple?ingredient=egg&ingredient=onion— search by repeatingingredientparams (returns simple JSON used by frontend).GET /api/recipes/search?ingredients=egg,onion— search by comma/newline separated ingredients (used by search page).
All API endpoints expect/return JSON and are implemented with async SQLAlchemy.
/— landing page with popular recipes carousel/catalog— paginated catalog/search— interactive search by ingredients/recipes/{id}— recipe detail page with like/bookmark/copy link buttons/bookmarks— list of recipes bookmarked from the current browser cookie
JavaScript modules of interest: app/static/js/search.js, actions.js, copy_link.js, carousel_swiper.js.
ingredientstable stores canonical ingredient names (with optionalaliasesJSON).recipesand arecipe_ingredientassociation table connect recipes and ingredients.anon_usertable stores anonymous user rows (identified by a signed cookie usingitsdangerous).recipe_actionstores likes/bookmarks linked to anon users (unique constraint on anon_id+recipe+action_type).
Project includes dev/test deps in pyproject.toml. Run tests with:
poetry run pytest
# or inside container if tests included
docker compose exec web pytest- If images fail to load locally, check
thumbnail_url/image_urlin DB fixtures; remote URLs may be blocked on some networks. - If you get DB errors during migrations, inspect ALEMBIC config and
DATABASE_URL(seealembic/env.py). - Use
docker compose exec web ls -la alembic/versionsto inspect migration files inside container.
Contributions are welcome — open issues or PRs with small, focused changes. For larger changes, describe the design first.
- Follow project formatting tools (
black,ruff,isort). - Add tests for new logic.
maxx — contact: m.petrykin@gmx.de (listed in pyproject.toml).