/** * All HTTP goes through this module (spec §8.2 rule 1). * No raw fetch() in components. Shapes mirror backend schemas.py (spec §8.3 rule 1). */ const BASE_URL = '' // same origin; Vite dev server proxies /api to the backend async function request(path, options = {}) { const resp = await fetch(`${BASE_URL}${path}`, { headers: { 'Content-Type': 'application/json' }, ...options, }) if (!resp.ok) { // Try to extract backend error detail for a better message let detail = `${resp.status}` try { const body = await resp.json() if (body.detail) detail = body.detail } catch { /* can't parse — use status code */ } throw new Error(`API ${options.method ?? 'GET'} ${path} failed: ${detail}`) } // 204 No Content (DELETE) — return success indicator if (resp.status === 204) return { ok: true } return resp.json() } export const api = { health: () => request('/api/health'), // Foods (spec §3.1) searchFoods: (q) => request(`/api/foods?q=${encodeURIComponent(q)}`), recentFoods: (limit = 10) => request(`/api/foods/recent?limit=${limit}`), getFood: (id) => request(`/api/foods/${id}`), createFood: (food) => request('/api/foods', { method: 'POST', body: JSON.stringify(food) }), // Daily log (spec §3.3) — dates are YYYY-MM-DD strings end-to-end (spec §8.3 rule 4) getLog: (date) => request(`/api/log?date=${date}`), addLogEntry: (entry) => request('/api/log', { method: 'POST', body: JSON.stringify(entry) }), updateLogEntry: (id, data) => request(`/api/log/${id}`, { method: 'PUT', body: JSON.stringify(data) }), deleteLogEntry: (id) => request(`/api/log/${id}`, { method: 'DELETE' }), getSummary: (date) => request(`/api/log/summary?date=${date}`), // Targets (spec §3.4) getCurrentTarget: () => request('/api/targets/current'), getTargets: () => request('/api/targets'), createTarget: (target) => request('/api/targets', { method: 'POST', body: JSON.stringify(target) }), // OFF proxy (spec §3.5) — the frontend never calls OFF directly offProduct: (barcode) => request(`/api/off/product/${barcode}`), offSearch: (q) => request(`/api/off/search?q=${encodeURIComponent(q)}`), }