Todos los artículos
tutorial javascript

Crea un contador de calorías con FoodBase

Tutorial paso a paso para crear una app sencilla de seguimiento de calorías con JavaScript y la API de FoodBase.

actualizado el 24 de julio de 2026 FoodBase Team 5 min de lectura

Qué vamos a construir

Un contador de calorías que permite a los usuarios buscar alimentos, registrar comidas y ver sus totales nutricionales diarios. Usaremos JavaScript puro y la API de FoodBase para que todo sea simple y no dependa de ningún framework.

Al final de este tutorial tendrás una app funcional que:

  • Busca en nuestra base de datos de 6,1 M de productos alimentarios
  • Muestra la información nutricional por porción
  • Lleva el total diario de calorías y macros

Requisitos previos

Paso 1: configura el cliente de la API

Crea una función reutilizable para llamar a la 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();
}

Paso 2: busca alimentos

Deja que los usuarios busquen por nombre. La API devuelve los resultados ordenados por relevancia:

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

Paso 3: obtén el detalle nutricional

Cuando el usuario elige un alimento, pide sus detalles completos, incluido el resumen nutricional:

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

El nutrition_summary incluye los 6 macros más comunes: energy_kcal, proteins_g, carbs_g, fat_g, sugars_g y fiber_g.

Paso 4: calcula por porción

La API devuelve todos los valores por 100 g. Para calcular por porción, multiplica por el peso de la porción:

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 }

Paso 5: registra las comidas del día

Guarda las comidas registradas y calcula los totales acumulados:

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 }

Paso 6: añade la lectura de códigos de barras

Si tu app tiene acceso a la cámara, puedes escanear códigos de barras y consultar productos al instante:

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

Paso 7: guarda los datos

En una app real querrás conservar el historial de comidas. Esta es una forma sencilla con 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 [];
}

Consejos para apps en producción

  • Guarda en caché los resultados de búsqueda en el cliente para reducir las llamadas a la API cuando los usuarios repiten las mismas búsquedas
  • Usa el endpoint bulk al cargar el historial de comidas — obtén todos los detalles de los alimentos en una sola petición en lugar de N llamadas individuales
  • Define objetivos diarios y muestra barras de progreso (objetivos habituales: 2000 kcal, 50 g de proteína, 25 g de fibra)
  • Gestiona bien el modo sin conexión — guarda en caché los alimentos vistos recientemente para que la app funcione sin red
  • Controla tu consumo en el panel para no pasarte de los límites de tu plan

Extra: registra comidas a partir de una foto

Si tienes créditos de IA para gastar (todos los planes incluyen algunos), el endpoint de comidas convierte la foto de un plato en elementos registrados con estimaciones de porción — una forma mucho más cómoda de registrar que buscar a mano:

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

Los tamaños de porción son estimaciones de la IA a partir de una sola foto, así que trata los números como un punto de partida que el usuario pueda ajustar — la respuesta incluye una cadena disclaimer que debes mostrar. Pruébalo primero en el playground de fotos.

Próximos pasos

  • Añade una función de planificación de comidas con alimentos guardados y macros objetivo
  • Integra la API de un rastreador de actividad para tener en cuenta el ejercicio
  • Crea una calculadora de recetas que sume los nutrientes de varios ingredientes
  • Usa el endpoint de nutrientes detallados para el seguimiento de micronutrientes (vitaminas, minerales)

Constrúyelo con FoodBase

6,1 M de productos, más de 40 nutrientes y análisis de alimentos con IA — gratis para empezar, sin tarjeta de crédito.