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().
Code Review: Add API endpoints for Home Assistant integrationThanks for this PR — the HA integration is a great use case and the overall approach is solid. Here are my findings across quality, correctness, and a few design concerns. Blocking Issues1. Blocking I/O in async handlers (
2. Duplicate pantry parsing logic
3. Negative
Design Concerns4. Full filesystem tree walk on every request Both 5.
6. Route ordering: In Code Quality7. Duplicated
8. Plain-text meal items silently dropped In 9. Check for unused
Test CoverageThe regex-heavy helpers (
DocumentationThe three plan/design/research docs total ~2900 lines and contain implementation-specific local paths ( Summary: The implementation is functionally correct and the API shape is well-considered. The three most important fixes before merge are: (1) switch to async-safe file I/O in pantry handlers, (2) deduplicate the pantry parsing logic, and (3) validate the |
- 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 integrationOverall this is a well-structured PR that adds useful endpoints cleanly. The code is readable, error handling is consistent, and the path-traversal protection is a good security touch. A few things worth addressing before merge: Bugs / Correctness1.
Consider extracting the counting logic into a shared helper that both 2. // pantry.rs:2856
let mut pantry_conf = load_pantry(&state).await.unwrap_or_default();If This is actually the same behavior as the pre-PR code ( Code Quality3. // menus.rs (collect_menus)
let name = entry.name().clone().unwrap_or_else(|| relative.to_string());If 4. The pantry-counting block in 5. // pantry.rs
let formats = [
"%Y-%m-%d", "%d.%m.%Y", "%d/%m/%Y", "%m/%d/%Y", ...
];
Performance6. Tree is rebuilt on every request
Not a blocker, but worth a follow-up issue to add caching (e.g. an Minor / Nits7. Large planning docs committed to Three multi-hundred-line design docs totalling ~2300 lines are included in 8. The design doc describes a What's done well
The main ask before merge is addressing the |
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