Add API endpoints for Home Assistant integration#271
Conversation
Add a new stats API endpoint that returns the total number of recipes and menus by recursively walking the recipe tree. This is the first of several endpoints needed for Home Assistant integration.
Adds a new API endpoint that recursively walks the recipe tree and returns all .menu files with their name and relative path, enabling Home Assistant to discover available menu files for config flow.
Add a handler that parses .menu files and returns structured JSON with sections grouped by meal type. Extracts dates from section names and times from meal headers via regex. This endpoint powers the HA Calendar entity by providing structured meal plan data.
Add GET /api/pantry/expiring?days=N and GET /api/pantry/depleted endpoints for Home Assistant integration. The expiring endpoint returns items expiring within N days (default 7) with days_remaining. The depleted endpoint returns items flagged as low stock via is_low().
- Switch pantry handlers from std::fs to tokio::fs for async I/O - Extract shared load_pantry() helper to deduplicate pantry parsing - Validate days parameter rejects negative values (400 Bad Request) - Add pantry_item_count, pantry_expiring_count, pantry_depleted_count to /api/stats - Move json_error and check_path to shared common.rs module - Reorder /menus before /menus/*path for clarity - Add doc comment explaining why plain text items are excluded from menu API
Code Review: Add API endpoints for Home Assistant integrationThis is a solid, well-structured addition. The code is clean and the endpoint design is sensible. A few issues to address: Security: No authentication on sensitive endpoints The new /api/pantry/expiring and /api/pantry/depleted endpoints expose household pantry data to anyone who can reach the server. Since CookCLI is designed for local use, this is an accepted trade-off, but it is worth noting in the README or docs so users know not to expose the server publicly. Bug: Ambiguous date format ordering in parse_date() The formats array includes both "%d/%m/%Y" and "%m/%d/%Y". Since "%d/%m/%Y" is tried first, a date like "03/04/2026" will be parsed as April 3rd regardless of locale intent. Consider documenting the supported formats clearly, removing the ambiguous slash formats, or requiring ISO 8601 (%Y-%m-%d) only. Inconsistency: Hardcoded 7-day threshold in /api/stats The pantry_expiring_count in StatsResponse uses a hardcoded 7-day window, while /api/pantry/expiring accepts a configurable ?days=N parameter. The stats response does not document what threshold was used, which makes it hard to interpret. Either expose the threshold in the response or make it consistent with the endpoint default. Code smell: AI prompt artifact in docs/plans/ The file docs/plans/2026-03-04-homeassistant-integration-plan.md begins with: This is an AI assistant prompt artifact that should be stripped before committing to the public repository. Design: Large plan/research/design docs committed to source Three large Markdown files are added under docs/plans/. These implementation notes are useful during development but are effectively dead weight in the release repository. Consider whether they belong in the wiki, an internal notes repo, or should be trimmed to just the design document (the research and plan files are mainly useful to the implementer, not future contributors). Minor: Text items silently dropped from /api/menus response The code explicitly discards LineItem::Text entries with a comment explaining that consumers should read the .menu file directly for raw text. This is a reasonable design decision, but it means plain-text connectors ("with", "served alongside", etc.) are lost. Consider noting this in the API documentation. Minor: Missing sort order on /api/pantry/depleted /api/pantry/expiring sorts by days_remaining (most urgent first), which is helpful. /api/pantry/depleted has no sort order -- consider sorting by section then name for consistent output. Summary: Good implementation overall. The ambiguous date parsing, the 7-day hardcoded threshold inconsistency, and the AI artifact in the plan doc are the most important issues to fix before merge. |
Merged main (v0.25.0) into ha-api-endpoints, preserving: - Async I/O (tokio::fs) in pantry handlers - Shared common.rs module for json_error/check_path - load_pantry() helper to deduplicate parsing - days validation in get_expiring - Pantry counts in /api/stats Incorporated from main: - find_todays_menu() function - pub visibility on collect_menus, extract_date, extract_meal_type, is_meal_header - Today's menu banner feature - Release v0.25.0 changes
Summary
GET /api/statsendpoint returning recipe and menu countsGET /api/menusendpoint listing all.menufilesGET /api/menus/*pathendpoint returning parsed menu with sections, meals, date/time extraction via regexGET /api/pantry/expiring?days=Nendpoint returning items expiring within N daysGET /api/pantry/depletedendpoint returning low-stock pantry itemsThese endpoints power the homeassistant-cookcli HACS custom component, which provides Calendar (meal plans from
.menufiles), Todo (shopping list), and Sensor entities for Home Assistant.Menu calendar mapping
Menu sections with dates in parentheses (
== Day 1 (2026-03-04) ==) are extracted via regex and mapped to HA calendar events. Meal type headers with times (Breakfast (08:30):) provide event start times. Sections without dates are ignored for calendar purposes but still included in shopping lists.Test plan
cargo fmtpassescargo clippypassescargo testpassescargo run -- server ./seedthencurl http://localhost:9080/api/statsreturns{"recipe_count":N,"menu_count":N}curl http://localhost:9080/api/menusreturns list of menu filescurl http://localhost:9080/api/menus/2%20Day%20Plan.menureturns parsed menu JSONcurl http://localhost:9080/api/pantry/expiring?days=30returns expiring itemscurl http://localhost:9080/api/pantry/depletedreturns depleted items