Search products across five open databases, and fix the broken OFF search (epic #43, backend) - #66
Merged
Merged
Conversation
Fixes the product name search and extends it beyond Open Food Facts.
The shipped search called the Open Food Facts **v2** API with a
`search_terms` parameter. v2 has no such parameter, so it was silently
ignored and the endpoint returned an arbitrary slice of the 4.6M-product
database — searching "peanut butter" returned Fromage Blanc and bottled
water. Open Food Facts is now queried through Search-a-licious
(search.openfoodfacts.org), which is relevance-ranked and returns the
image URLs the suggestion list needs. Its legacy cgi/search.pl endpoint
is frequently unavailable under load, so it is not used as a fallback.
Search now fans out concurrently to five sources, grouped by source:
- Open Food Facts (Search-a-licious)
- Open Beauty Facts (cgi/search.pl)
- Open Products Facts (cgi/search.pl)
- Open Pet Food Facts (cgi/search.pl)
- USDA FoodData Central (FDC API)
The lower-traffic OFF siblings have no Search-a-licious index but their
CGI search works fine. USDA covers the generic/whole foods ("bananas,
raw") that the barcode-keyed databases do not carry.
Each group carries its own "see more" link. Sources returning nothing are
omitted, and a source that times out, rate-limits or dies degrades to an
empty group rather than failing the whole search.
Because USDA foods are keyed by FDC id rather than barcode, selecting a
suggestion now needs the source: GET /barcode/product?source=&id=.
GET /barcode/{barcode} and the flat results/search_url fields are kept so
the deployed frontend keeps working until it moves to the grouped shape.
USDA needs a free API key (USDA_FDC_API_KEY); it defaults to the
rate-limited DEMO_KEY, and setting it empty drops USDA from the search.
Covers all three touched files at 100%, including a regression test
asserting the OFF query goes to Search-a-licious with `q` and that
`search_terms` never comes back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
untraceablez
force-pushed
the
feat/multi-source-product-search
branch
from
July 27, 2026 16:49
174f558 to
5277a4e
Compare
The Sonar gate failed the build on two cognitive-complexity violations: _parse_usda_product 16 -> allowed 15 _parse_product_data 31 -> allowed 15 _parse_product_data's complexity is long-standing -- its nutriment block was 19 hand-written three-way `or` chains -- but the source parameter added in the previous commit touched the signature, so Clean-as-You-Code counts the whole function as new and the zero-new-violations condition fails. Both nutrient blocks become table-driven: _OFF_NUTRIMENT_MAP pairs each Open Food Facts prefix with our key and the helper does the serving -> 100g -> bare fallback in a loop, and the USDA nutrient loop and serving-size join move to their own helpers. Verified behaviour-identical rather than assumed: a differential harness ran the old inline block and the new helper over four real Open Food Facts products (up to 13 populated keys) plus edge cases for absent nutriments, empty nutriments, serving-beats-100g, bare-key fallback, and the quirk where a 0 value is falsy and falls through to the next candidate. Zero mismatches, and key ordering is preserved. Coverage stays at 100%; 417 backend tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Jul 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #43. Backend half; the frontend PR that renders the grouped results follows.
The bug
The product name search shipped in #59 called the Open Food Facts v2 API with a
search_termsparameter. v2 has no such parameter — it was silently ignored, so the endpoint returned an arbitrary slice of the 4.6M-product database:The existing tests didn't catch it because they mock the transport — the payload shape was right, only the request was wrong. There's now a regression test asserting the OFF query goes to Search-a-licious with
q, and thatsearch_termsnever comes back.Open Food Facts is now queried through Search-a-licious (
search.openfoodfacts.org), which is relevance-ranked and returns the image URLs the suggestion list needs. Its legacycgi/search.plendpoint is currently serving "Page temporarily unavailable" under load, so it isn't used as a fallback.Multi-source search
Search fans out concurrently to five sources and groups the hits:
cgi/search.plcgi/search.plcgi/search.plThe lower-traffic OFF siblings have no Search-a-licious index, but their CGI search works fine. USDA covers the generic/whole foods (
bananas, raw) that the barcode-keyed databases don't carry.Each group carries its own "see more" link. Sources returning nothing are omitted, and a source that times out, rate-limits or dies degrades to an empty group rather than failing the whole search.
Live output for
q=peanut+butter:API changes
GET /barcode/searchgainsgroups: [{source, label, results, search_url}]. Suggestions now carrysource,source_labelandidalongsidebarcode.GET /barcode/product?source=&id=— selecting a suggestion needs the source, because USDA foods are keyed by FDC id rather than barcode. Unknown sources 400 with the supported list.GET /barcode/{barcode}and the flatresults/search_urlfields are kept, so the currently deployed frontend keeps working until it moves to the grouped shape.Config
USDA_FDC_API_KEYdefaults to the rate-limitedDEMO_KEY(~30 req/hr/IP); a free key comes from https://fdc.nal.usda.gov/api-key-signup. Setting it empty drops USDA from search entirely.Testing
417 passed— full backend suite, no regressions.barcode_service.py172,product_sources.py30,api/v1/barcode.py26).off/obf/opff/usda, the 400 on an unknown source, and the legacy/barcode/{barcode}route.🤖 Generated with Claude Code