diff --git a/apps/backend/.env.example b/apps/backend/.env.example index 701e422..2b28232 100644 --- a/apps/backend/.env.example +++ b/apps/backend/.env.example @@ -19,3 +19,8 @@ VAPID_SUBJECT=mailto:admin@example.com # Expo Push Notifications (mobile). Get token from: # https://expo.dev/accounts/[username]/settings/access-tokens EXPO_ACCESS_TOKEN= + +# Open Food Facts (optional, improves rate limits) +# Register at: https://world.openfoodfacts.org/ +OFF_USERNAME= +OFF_PASSWORD= diff --git a/apps/backend/off-service.js b/apps/backend/off-service.js index 9c5a3bd..988ebc9 100644 --- a/apps/backend/off-service.js +++ b/apps/backend/off-service.js @@ -4,6 +4,20 @@ import redisClient from './redis-client.js'; const OFF_API_BASE = 'https://world.openfoodfacts.org'; const CACHE_TTL = 3600; +// Open Food Facts authentication (optional, improves rate limits) +const OFF_USERNAME = process.env.OFF_USERNAME; +const OFF_PASSWORD = process.env.OFF_PASSWORD; + +function getOffAuth() { + if (OFF_USERNAME && OFF_PASSWORD) { + return { + username: OFF_USERNAME, + password: OFF_PASSWORD, + }; + } + return null; +} + export function transformOFFProduct(offProduct) { if (!offProduct || !offProduct._id || !offProduct.product_name) { return null; @@ -53,6 +67,7 @@ export async function searchBabyProducts(query) { } console.log(`Fetching from OFF API: ${searchTerm}`); + const auth = getOffAuth(); const response = await axios.get(`${OFF_API_BASE}/cgi/search.pl`, { params: { search_terms: searchTerm, @@ -63,6 +78,7 @@ export async function searchBabyProducts(query) { }, timeout: 10000, validateStatus: (status) => status === 200, + ...(auth && { auth }), }); // Check if response is actually JSON (OFF sometimes returns HTML on error) @@ -108,8 +124,11 @@ export async function getBabyProductDetails(barcode) { } console.log(`Fetching OFF product details: ${barcode}`); + const auth = getOffAuth(); const response = await axios.get(`${OFF_API_BASE}/api/v2/product/${barcode}.json`, { timeout: 10000, + validateStatus: (status) => status === 200, + ...(auth && { auth }), }); if (response.data && response.data.product) {