Initial project scaffold: FastAPI backend + Svelte 5 frontend
Backend (uv): FastAPI app with routers (foods, log, targets, OFF proxy), SQLAlchemy models, Pydantic schemas, migration runner + 0001 initial schema, example pytest suite (7 tests). Frontend (npm): Vite 7 + Svelte 5 runes, lib/ (api, stores, scanner, format) per spec §7, placeholder components, example vitest suite (4 tests). SPEC.md §1: registered uvicorn and Vitest (rule §8.3.3).
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
"""OpenFoodFacts proxy (spec §3.5). All OFF calls go through this router.
|
||||
|
||||
OFF etiquette (spec §8.1 rule 10): descriptive User-Agent, timeouts, and
|
||||
kcal-vs-kJ normalization in exactly one module. Tests mock at the httpx
|
||||
boundary — never hit the real OFF API (spec §8.4).
|
||||
"""
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter
|
||||
|
||||
OFF_BASE_URL = "https://world.openfoodfacts.org"
|
||||
OFF_USER_AGENT = "CalCount/0.1 (personal self-hosted calorie counter)"
|
||||
OFF_TIMEOUT = 10.0
|
||||
|
||||
router = APIRouter(prefix="/api/off", tags=["off"])
|
||||
|
||||
|
||||
@router.get("/product/{barcode}")
|
||||
def get_product(barcode: str):
|
||||
"""Proxy a product lookup by barcode. Returns raw OFF JSON for now.
|
||||
|
||||
TODO: normalize to our foods schema (spec §3.5) in one shared module.
|
||||
"""
|
||||
resp = httpx.get(
|
||||
f"{OFF_BASE_URL}/api/v2/product/{barcode}",
|
||||
headers={"User-Agent": OFF_USER_AGENT},
|
||||
timeout=OFF_TIMEOUT,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
Reference in New Issue
Block a user