e047d884b6
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).
31 lines
948 B
Python
31 lines
948 B
Python
"""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()
|