Всички публикации
tutorial javascript

Създай брояч на калории с FoodBase

Урок стъпка по стъпка за създаване на просто приложение за броене на калории с JavaScript и FoodBase API.

обновено на 24 юли 2026 г. FoodBase Team 4 мин. четене

Какво ще създадем

Брояч на калории, в който потребителите търсят храни, записват хранения и виждат дневните си хранителни суми. Ще използваме чист JavaScript и FoodBase API, за да е всичко просто и независимо от фреймуърк.

В края на урока ще имаш работещо приложение, което:

  • търси в базата ни от 6,1 млн. хранителни продукта
  • показва хранителните стойности на порция
  • следи дневните суми на калории и макроси

Какво ти трябва

Стъпка 1: Настрой API клиента

Създай функция за многократна употреба, с която да извикваш API-то:

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();
}

Стъпка 2: Търсене на храни

Позволи на потребителите да търсят по име. API-то връща резултатите, подредени по релевантност:

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"})`);
});

Стъпка 3: Подробни хранителни стойности

Когато потребителят избере храна, вземи пълните ѝ данни, включително обобщението на хранителните стойности:

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`);

nutrition_summary съдържа 6-те най-често срещани макроса: energy_kcal, proteins_g, carbs_g, fat_g, sugars_g и fiber_g.

Стъпка 4: Изчисляване на порция

API-то връща всички стойности на 100 г. За да изчислиш стойностите на порция, умножи по теглото на порцията:

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 }

Стъпка 5: Записване на дневните хранения

Запазвай записаните хранения и изчислявай текущите суми:

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 }

Стъпка 6: Добави сканиране на баркодове

Ако приложението ти има достъп до камерата, можеш да сканираш баркодове и веднага да намираш продуктите:

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"
}

Стъпка 7: Запазване на данните

В истинско приложение ще искаш да пазиш историята на храненията. Ето един прост подход с 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 [];
}

Съвети за приложения в продукция

  • Кеширай резултатите от търсенето на клиента, за да намалиш API заявките, когато потребителите търсят същите думи отново
  • Използвай bulk ендпойнта при зареждане на историята на храненията — вземи данните за всички храни с една заявка вместо с N отделни
  • Задай дневни цели и показвай прогрес лентите (често срещани цели: 2000 kcal, 50 г белтъчини, 25 г фибри)
  • Справяй се добре с офлайн режим — кеширай наскоро разглежданите храни, за да работи приложението и без мрежа
  • Следи използването си в таблото, за да останеш в лимитите на плана си

Бонус: записвай хранения от снимка

Ако имаш AI кредити (всеки план включва някакви), meal ендпойнтът превръща снимка на чиния в записани продукти с оценка на порциите — много по-лесен начин за записване от търсенето:

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;
}

Размерите на порциите са AI оценки от една снимка, затова приемай числата като отправна точка, която потребителят може да коригира — отговорът съдържа низ disclaimer, който трябва да показваш. Пробвай първо във фото playground-а.

Следващи стъпки

  • Добави функция за планиране на храненията със запазени храни и целеви макроси
  • Интегрирай API на фитнес тракер, за да отчиташ и физическата активност
  • Създай калкулатор за рецепти, който сумира хранителните вещества на няколко съставки
  • Използвай ендпойнта за подробни хранителни вещества, за да следиш микроелементите (витамини, минерали)

Създай го с FoodBase

6,1 млн. продукта, над 40 хранителни вещества и AI анализ на храни — безплатен старт, без кредитна карта.