Was wir bauen
Einen Kalorienzähler, mit dem Nutzer nach Lebensmitteln suchen, Mahlzeiten erfassen und ihre täglichen Nährwertsummen sehen. Wir verwenden Vanilla JavaScript und die FoodBase API, damit alles einfach und framework-unabhängig bleibt.
Am Ende dieses Tutorials hast du eine funktionierende App, die:
- unsere Datenbank mit 6,1 Mio. Lebensmittelprodukten durchsucht
- Nährwerte pro Portion anzeigt
- tägliche Kalorien- und Makro-Summen mitzählt
Voraussetzungen
- Ein FoodBase-Konto (kostenlos registrieren)
- Einen API-Schlüssel aus dem Dashboard
- Grundkenntnisse in JavaScript
Schritt 1: Den API-Client einrichten
Leg eine wiederverwendbare Funktion für API-Aufrufe an:
const API_KEY = "food_your_key_here";
const BASE_URL = "https://foodbase.dev/v1";
async function foodApi(path) {
const res = await fetch(`${BASE_URL}${path}`, {
headers: { "X-API-Key": API_KEY },
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error || `HTTP ${res.status}`);
}
return res.json();
}
Schritt 2: Nach Lebensmitteln suchen
Lass Nutzer nach Namen suchen. Die API liefert die Ergebnisse nach Relevanz sortiert:
async function searchFoods(query, limit = 10) {
const params = new URLSearchParams({ q: query, limit });
const data = await foodApi(`/foods/search?${params}`);
return data.data; // array of food items
}
// Usage
const results = await searchFoods("chicken breast");
console.log(`Found ${results.length} results`);
results.forEach(food => {
console.log(`${food.name_default} (${food.brand || "Generic"})`);
});
Schritt 3: Nährwertdetails abrufen
Wählt der Nutzer ein Lebensmittel aus, holst du die vollständigen Details inklusive Nährwertübersicht:
async function getFoodWithNutrition(foodId) {
return foodApi(`/foods/${foodId}`);
}
const food = await getFoodWithNutrition("abc-123");
console.log(`${food.name_default}: ${food.nutrition_summary.energy_kcal} kcal/100g`);
Die nutrition_summary enthält die 6 häufigsten Makros: energy_kcal, proteins_g, carbs_g, fat_g, sugars_g und fiber_g.
Schritt 4: Pro Portion rechnen
Die API liefert alle Werte pro 100 g. Für Werte pro Portion multiplizierst du mit dem Portionsgewicht:
function calculateServing(nutritionPer100g, servingGrams) {
if (!nutritionPer100g) return null;
const factor = servingGrams / 100;
return {
calories: Math.round((nutritionPer100g.energy_kcal || 0) * factor),
protein: round1((nutritionPer100g.proteins_g || 0) * factor),
carbs: round1((nutritionPer100g.carbs_g || 0) * factor),
fat: round1((nutritionPer100g.fat_g || 0) * factor),
fiber: round1((nutritionPer100g.fiber_g || 0) * factor),
};
}
function round1(n) {
return Math.round(n * 10) / 10;
}
// Example: 100g chicken breast
const serving = calculateServing(food.nutrition_summary, 150);
// → { calories: 248, protein: 46.5, carbs: 0, fat: 5.3, fiber: 0 }
Schritt 5: Tägliche Mahlzeiten erfassen
Speicher die erfassten Mahlzeiten und berechne laufende Summen:
const meals = [];
function addMeal(food, servingGrams) {
const nutrition = calculateServing(food.nutrition_summary, servingGrams);
meals.push({
name: food.name_default,
brand: food.brand,
grams: servingGrams,
...nutrition,
addedAt: new Date(),
});
return nutrition;
}
function getDailyTotals() {
return meals.reduce(
(totals, meal) => ({
calories: totals.calories + (meal.calories || 0),
protein: round1(totals.protein + (meal.protein || 0)),
carbs: round1(totals.carbs + (meal.carbs || 0)),
fat: round1(totals.fat + (meal.fat || 0)),
fiber: round1(totals.fiber + (meal.fiber || 0)),
}),
{ calories: 0, protein: 0, carbs: 0, fat: 0, fiber: 0 },
);
}
// Log a meal
addMeal(food, 150);
console.log(getDailyTotals());
// → { calories: 248, protein: 46.5, carbs: 0, fat: 5.3, fiber: 0 }
Schritt 6: Barcode-Scanning ergänzen
Hat deine App Zugriff auf die Kamera, kannst du Barcodes scannen und Produkte sofort nachschlagen:
async function lookupBarcode(barcode) {
try {
return await foodApi(`/foods/barcode/${barcode}`);
} catch (err) {
if (err.message.includes("Not found")) {
return null; // Product not in database
}
throw err;
}
}
// After scanning a barcode with a camera library
const product = await lookupBarcode("5449000000996");
if (product) {
console.log(`Found: ${product.name_default} by ${product.brand}`);
// → "Found: Original Taste by Coca-Cola"
}
Schritt 7: Daten speichern
In einer echten App willst du den Mahlzeitenverlauf speichern. Hier ein einfacher Ansatz mit localStorage:
function saveMeals() {
localStorage.setItem("meals", JSON.stringify(meals));
localStorage.setItem("mealsDate", new Date().toISOString().slice(0, 10));
}
function loadMeals() {
const today = new Date().toISOString().slice(0, 10);
const savedDate = localStorage.getItem("mealsDate");
if (savedDate === today) {
const saved = localStorage.getItem("meals");
return saved ? JSON.parse(saved) : [];
}
// New day — reset
return [];
}
Tipps für Apps in Produktion
- Cache Suchergebnisse im Client, um API-Aufrufe zu sparen, wenn Nutzer dieselben Begriffe erneut suchen
- Nutz den Bulk-Endpunkt beim Laden des Mahlzeitenverlaufs — hol alle Lebensmitteldetails in einer Anfrage statt in N einzelnen Aufrufen
- Setz Tagesziele und zeig Fortschrittsbalken (übliche Ziele: 2000 kcal, 50 g Eiweiß, 25 g Ballaststoffe)
- Geh sauber mit Offline-Situationen um — cache zuletzt angesehene Lebensmittel, damit die App auch ohne Netz funktioniert
- Behalte deine Nutzung im Dashboard im Blick, um innerhalb der Limits deines Plans zu bleiben
Bonus: Mahlzeiten per Foto erfassen
Wenn du KI-Credits übrig hast (jeder Plan enthält welche), macht der Meal-Endpunkt aus einem Tellerfoto erfasste Einträge mit geschätzten Portionen — viel bequemer als das Suchen:
async function analyzeMealPhoto(file) {
const form = new FormData();
form.append("image", file);
const res = await fetch("https://foodbase.dev/v1/vision/meal", {
method: "POST",
headers: { "X-API-Key": API_KEY },
body: form,
});
if (!res.ok) throw new Error(`Vision error: ${res.status}`);
const meal = await res.json();
// meal.items: [{ dish, portion_g_est, match: { estimated_kcal, ... } }]
// meal.estimated_total_kcal: number | null
return meal;
}
Portionsgrößen sind KI-Schätzungen aus einem einzigen Foto. Behandle die Zahlen also als Ausgangspunkt, den Nutzer anpassen können — die Antwort enthält einen disclaimer-String, den du anzeigen solltest. Probier es zuerst im Foto-Playground aus.
Nächste Schritte
- Ergänze eine Mahlzeitenplanung mit gespeicherten Lebensmitteln und Makro-Zielen
- Bind die API eines Fitness-Trackers an, um Sport mit einzurechnen
- Bau einen Rezeptrechner, der die Nährwerte mehrerer Zutaten summiert
- Nutz den detaillierten Nutrients-Endpunkt, um Mikronährstoffe (Vitamine, Mineralstoffe) zu tracken
Weitere Beiträge
Bau es mit FoodBase
6,1 Mio. Produkte, über 40 Nährstoffe und KI-Lebensmittelanalyse — kostenlos starten, ohne Kreditkarte.