Cómo Usar la API de Firebase: Guía Completa de Integración (2026)

Ashley Innocent

Ashley Innocent

23 March 2026

Cómo Usar la API de Firebase: Guía Completa de Integración (2026)

Apidog para empresas

Despliegue local

SSO & RBAC

Conforme con SOC 2

Explorar Apidog Enterprise

Estás construyendo una aplicación. Los usuarios necesitan iniciar sesión. Los datos deben sincronizarse en tiempo real. Los archivos necesitan almacenamiento. Podrías levantar servidores, configurar bases de datos y gestionar la infraestructura durante semanas. O podrías usar Firebase.

Firebase potencia más de 1.5 millones de aplicaciones, incluyendo The New York Times, Duolingo y Alibaba. Los desarrolladores lo eligen porque elimina la complejidad del backend. Te enfocas en las características, no en el mantenimiento del servidor. Pero la API de Firebase tiene sus peculiaridades. Los flujos de autenticación confunden a los principiantes. Las reglas de la base de datos complican a los desarrolladores experimentados. Las Cloud Functions parecen mágicas hasta que entiendes los activadores.

He integrado Firebase en aplicaciones de producción que atienden a millones de usuarios. He cometido todos los errores posibles: expuse claves de cuentas de servicio, escribí consultas ineficientes, implementé funciones defectuosas. Esta guía destila esas lecciones.

Aprenderás autenticación, operaciones de base de datos, Cloud Functions y almacenamiento. Verás código funcional, no solo teoría. Evitarás los problemas que causan incendios en producción.

💡
Probar las API de Firebase se vuelve más fácil con herramientas adecuadas de cliente API. Apidog te permite organizar puntos finales, probar flujos de autenticación y compartir colecciones con tu equipo. Mostraremos dónde encaja naturalmente en el flujo de trabajo.
button

¿Qué es la API de Firebase y por qué es importante?

Firebase no es una única API. Es un conjunto de servicios de backend a los que se accede a través de SDKs unificados y puntos finales REST.

Servicios Principales de Firebase

Servicio Propósito Tipo de API
Authentication Inicio de sesión e identidad de usuario SDK + REST
Firestore Database Base de datos de documentos NoSQL SDK + REST
Realtime Database Sincronización en tiempo real de JSON SDK + REST
Cloud Storage Almacenamiento de archivos y CDN SDK + REST
Cloud Functions Cómputo sin servidor CLI de despliegue
Hosting Alojamiento web estático CLI de despliegue
Cloud Messaging Notificaciones push HTTP v1 API

Cuándo Firebase Tiene Sentido

Firebase resuelve bien problemas específicos:

Usa Firebase cuando:

Omite Firebase cuando:

La Arquitectura de la API de Firebase

Firebase utiliza un enfoque híbrido:

┌─────────────────────────────────────────────────────────┐
│                    Tu Aplicación                         │
├─────────────────────────────────────────────────────────┤
│  Firebase SDK (Cliente)                                  │
│  - Maneja automáticamente los tokens de autenticación    │
│  - Gestiona la caché sin conexión                        │
│  - Escuchas en tiempo real                               │
└─────────────────────────────────────────────────────────┘
                          │
                          │ HTTPS + WebSocket
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   Backend de Firebase                    │
├──────────────┬──────────────┬──────────────┬────────────┤
│   Servicio   │   Base de    │   Servicio   │  Tiempo de │
│  de Autent.  │    Datos     │  de Almac.   │  Ejecución │
│              │   Firestore  │              │  de Func.  │
└──────────────┴──────────────┴──────────────┴────────────┘

Los SDK de cliente abstraen la capa HTTP. Bajo el capó, cada operación se traduce en llamadas a la API REST con autenticación JWT.

Autenticación de Firebase: Configuración Completa

La autenticación es tu primera integración de Firebase. Si lo haces mal, todo lo demás falla.

Paso 1: Crear Proyecto de Firebase

  1. Ve a la Consola de Firebase

Haz clic en "Agregar proyecto" e ingresa el nombre del proyecto (sin espacios)

Habilita Google Analytics (opcional pero recomendado)

Haz clic en "Crear proyecto"

Espera 30 segundos para el aprovisionamiento. Verás el panel del proyecto.

Paso 2: Registrar Tu Aplicación

Para Aplicaciones Web:

// En la Consola de Firebase > Configuración del Proyecto > General
// Haz clic en "Agregar aplicación" > Icono web

// Registrar aplicación web
const firebaseConfig = {
  apiKey: "AIzaSyDxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  authDomain: "tu-app.firebaseapp.com",
  projectId: "tu-app",
  storageBucket: "tu-app.appspot.com",
  messagingSenderId: "123456789012",
  appId: "1:123456789012:web:abc123def456"
};

// Inicializar Firebase
import { initializeApp } from 'firebase/app';
const app = initializeApp(firebaseConfig);

Para Aplicaciones iOS:

Descarga GoogleService-Info.plist y agrégalo al proyecto Xcode. Asegúrate de que "Target Membership" incluya tu aplicación.

Para Aplicaciones Android:

Descarga google-services.json y colócalo en el directorio app/. Agrégalo a build.gradle:

// build.gradle a nivel de proyecto
buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.4.0'
    }
}

// build.gradle a nivel de aplicación
plugins {
    id 'com.google.gms.google-services'
}

Paso 3: Habilitar Métodos de Autenticación

En la Consola de Firebase > Autenticación > Método de inicio de sesión:

  1. Correo electrónico/Contraseña: Habilitar para registro tradicional
  2. Google: Agrega la huella digital de tu certificado SHA-1 (Android) o el ID de paquete (iOS)
  3. Apple: Requerido para aplicaciones iOS si habilitas cualquier inicio de sesión social
  4. Teléfono: Habilitar para autenticación por SMS (requiere facturación)

Paso 4: Implementar Flujo de Autenticación

Registro con Correo Electrónico/Contraseña:

import {
  createUserWithEmailAndPassword,
  getAuth,
  updateProfile
} from 'firebase/auth';

const auth = getAuth(app);

async function signUp(email, password, displayName) {
  try {
    const userCredential = await createUserWithEmailAndPassword(
      auth,
      email,
      password
    );

    // Establecer nombre de visualización
    await updateProfile(userCredential.user, {
      displayName: displayName
    });

    console.log('Usuario creado:', userCredential.user.uid);
    return userCredential.user;
  } catch (error) {
    // Manejar códigos de error específicos
    switch (error.code) {
      case 'auth/email-already-in-use':
        throw new Error('Este correo electrónico ya está registrado');
      case 'auth/weak-password':
        throw new Error('La contraseña debe tener al menos 6 caracteres');
      case 'auth/invalid-email':
        throw new Error('Dirección de correo electrónico inválida');
      default:
        throw new Error('Fallo al registrarse: ' + error.message);
    }
  }
}

Inicio de Sesión con Correo Electrónico/Contraseña:

import {
  signInWithEmailAndPassword,
  signOut
} from 'firebase/auth';

async function signIn(email, password) {
  try {
    const userCredential = await signInWithEmailAndPassword(
      auth,
      email,
      password
    );

    const user = userCredential.user;

    // Obtener token de ID para llamadas a la API
    const idToken = await user.getIdToken();
    console.log('Token de autenticación:', idToken);

    return user;
  } catch (error) {
    switch (error.code) {
      case 'auth/user-not-found':
        throw new Error('No existe cuenta con este correo electrónico');
      case 'auth/wrong-password':
        throw new Error('Contraseña incorrecta');
      case 'auth/too-many-requests':
        throw new Error('Demasiados intentos. Inténtalo de nuevo más tarde');
      default:
        throw new Error('Fallo al iniciar sesión');
    }
  }
}

async function logOut() {
  await signOut(auth);
  console.log('Usuario cerró sesión');
}

Inicio de Sesión con Google (Web):

import {
  GoogleAuthProvider,
  signInWithPopup
} from 'firebase/auth';

async function signInWithGoogle() {
  const provider = new GoogleAuthProvider();

  // Solicitar ámbitos adicionales
  provider.addScope('email');
  provider.addScope('profile');

  try {
    const result = await signInWithPopup(auth, provider);
    const user = result.user;

    // Acceder al token de OAuth de Google
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const googleAccessToken = credential.accessToken;

    return user;
  } catch (error) {
    if (error.code === 'auth/popup-closed-by-user') {
      throw new Error('Inicio de sesión cancelado');
    }
    throw new Error('Fallo en el inicio de sesión con Google');
  }
}

Paso 5: Proteger Rutas con el Estado de Autenticación

import { onAuthStateChanged } from 'firebase/auth';

// Suscribirse a cambios en el estado de autenticación
onAuthStateChanged(auth, (user) => {
  if (user) {
    // El usuario ha iniciado sesión
    console.log('Usuario:', user.email);
    // Redirigir al panel de control
    window.location.href = '/dashboard';
  } else {
    // El usuario ha cerrado sesión
    console.log('Ningún usuario');
    // Redirigir al inicio de sesión
    window.location.href = '/login';
  }
});

Errores Comunes de Autenticación

Error 1: No manejar la actualización del token

El SDK de Firebase actualiza automáticamente los tokens. Pero si almacenas los tokens en caché en el servidor, expiran después de 1 hora. Siempre verifica los tokens en cada solicitud o implementa una lógica de actualización.

Error 2: Exponer credenciales de administrador en el código del cliente

Nunca uses claves de cuenta de servicio en aplicaciones cliente. Las cuentas de servicio omiten las reglas de seguridad. Úsalas solo en entornos de servidor confiables.

Error 3: Omitir la verificación de correo electrónico

import { sendEmailVerification } from 'firebase/auth';

async function sendVerificationEmail(user) {
  await sendEmailVerification(user);
  console.log('Correo electrónico de verificación enviado');
}

// Verificar estado de verificación
if (!auth.currentUser.emailVerified) {
  console.log('Correo electrónico no verificado');
  // Restringir acceso
}

Base de Datos Firestore: Operaciones y Consultas

Firestore es la base de datos NoSQL de Firebase. Los documentos se organizan en colecciones. Las consultas se escalan automáticamente.

Estructura de Datos

tu-proyecto (raíz)
└── users (colección)
    ├── userId123 (documento)
    │   ├── name: "John"
    │   ├── email: "john@example.com"
    │   └── posts (subcolección)
    │       ├── postId1 (documento)
    │       └── postId2 (documento)
    └── userId456 (documento)

Inicializar Firestore

import { getFirestore } from 'firebase/firestore';

const db = getFirestore(app);

Crear Documentos

import {
  collection,
  addDoc,
  setDoc,
  doc
} from 'firebase/firestore';

// Opción 1: ID autogenerado
async function createUser(userData) {
  const docRef = await addDoc(collection(db, 'users'), userData);
  console.log('Documento escrito con ID:', docRef.id);
  return docRef.id;
}

// Opción 2: ID personalizado
async function createUserWithId(userId, userData) {
  await setDoc(doc(db, 'users', userId), userData);
  console.log('Documento escrito con ID personalizado:', userId);
}

// Uso
const userId = await createUser({
  name: 'Alice',
  email: 'alice@example.com',
  createdAt: new Date(),
  role: 'user'
});

Leer Documentos

import {
  getDoc,
  getDocs,
  query,
  where,
  orderBy,
  limit
} from 'firebase/firestore';

// Obtener un solo documento
async function getUser(userId) {
  const docRef = doc(db, 'users', userId);
  const docSnap = await getDoc(docRef);

  if (docSnap.exists()) {
    return docSnap.data();
  } else {
    throw new Error('Usuario no encontrado');
  }
}

// Consultar con filtros
async function getUsersByRole(role) {
  const q = query(
    collection(db, 'users'),
    where('role', '==', role),
    orderBy('createdAt', 'desc'),
    limit(10)
  );

  const querySnapshot = await getDocs(q);
  const users = [];

  querySnapshot.forEach((doc) => {
    users.push({ id: doc.id, ...doc.data() });
  });

  return users;
}

// Uso
const adminUsers = await getUsersByRole('admin');
console.log('Usuarios administradores:', adminUsers);

Actualizar Documentos

import {
  updateDoc,
  increment,
  arrayUnion,
  arrayRemove
} from 'firebase/firestore';

async function updateUser(userId, updates) {
  const userRef = doc(db, 'users', userId);
  await updateDoc(userRef, updates);
}

// Operaciones atómicas
await updateUser('userId123', {
  loginCount: increment(1),
  tags: arrayUnion('premium', 'beta-tester'),
  lastLogin: new Date()
});

// Eliminar de una matriz
await updateUser('userId123', {
  tags: arrayRemove('beta-tester')
});

Eliminar Documentos

import { deleteDoc } from 'firebase/firestore';

async function deleteUser(userId) {
  await deleteDoc(doc(db, 'users', userId));
  console.log('Usuario eliminado');
}

Escuchas en Tiempo Real

import { onSnapshot } from 'firebase/firestore';

// Escuchar un solo documento
const unsubscribe = onSnapshot(
  doc(db, 'users', userId),
  (doc) => {
    console.log('Usuario actualizado:', doc.data());
  },
  (error) => {
    console.error('Error de escucha:', error);
  }
);

// Escuchar resultados de consulta
const q = query(collection(db, 'posts'), where('published', '==', true));

const unsubscribeQuery = onSnapshot(q, (snapshot) => {
  const posts = snapshot.docs.map(doc => ({
    id: doc.id,
    ...doc.data()
  }));
  console.log('Publicaciones publicadas:', posts);
});

// Dejar de escuchar
unsubscribe();
unsubscribeQuery();

Reglas de Seguridad de Firestore

Sin reglas adecuadas, cualquiera puede leer tus datos. Establece reglas en la Consola de Firebase > Firestore > Reglas:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // Función auxiliar
    function isAuthenticated() {
      return request.auth != null;
    }

    function isOwner(userId) {
      return request.auth.uid == userId;
    }

    // Colección de usuarios
    match /users/{userId} {
      allow read: if isAuthenticated();
      allow create: if isAuthenticated() && isOwner(userId);
      allow update, delete: if isOwner(userId);
    }

    // Colección de publicaciones
    match /posts/{postId} {
      allow read: if true; // Lectura pública
      allow create: if isAuthenticated();
      allow update, delete: if resource.data.authorId == request.auth.uid;
    }

    // Subcolección privada
    match /users/{userId}/private/{document} {
      allow read, write: if isOwner(userId);
    }
  }
}

Limitaciones de Consulta

Firestore tiene restricciones:

Solución para consultas OR:

// En lugar de: where('status', '==', 'active') OR where('status', '==', 'pending')

const activeQuery = query(
  collection(db, 'tasks'),
  where('status', '==', 'active')
);

const pendingQuery = query(
  collection(db, 'tasks'),
  where('status', '==', 'pending')
);

const [activeSnap, pendingSnap] = await Promise.all([
  getDocs(activeQuery),
  getDocs(pendingQuery)
]);

// Fusionar resultados en el cliente

Cloud Functions: Lógica de Backend sin Servidor

Cloud Functions ejecutan código backend sin gestionar servidores. Se activan con cambios en la base de datos, solicitudes HTTP o eventos programados.

Configuración

# Instalar Firebase CLI
npm install -g firebase-tools

# Iniciar sesión
firebase login

# Inicializar funciones en tu proyecto
firebase init functions

# Seleccionar: JavaScript, ESLint sí, Express.js no

Funciones HTTP (Puntos Finales de API)

// functions/index.js
const { onRequest } = require('firebase-functions/v2/https');
const admin = require('firebase-admin');

admin.initializeApp();
const db = admin.firestore();

// Punto final público
exports.getPublicData = onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');

  try {
    const snapshot = await db.collection('public').get();
    const data = snapshot.docs.map(doc => doc.data());
    res.json({ success: true, data });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Punto final protegido (verificar token de autenticación)
exports.getUserProfile = onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');

  // Obtener token del encabezado Authorization
  const authHeader = req.headers.authorization || '';
  const token = authHeader.split('Bearer ')[1];

  if (!token) {
    return res.status(401).json({ error: 'No autorizado' });
  }

  try {
    // Verificar token
    const decodedToken = await admin.auth().verifyIdToken(token);
    const userId = decodedToken.uid;

    // Obtener datos del usuario
    const userDoc = await db.collection('users').doc(userId).get();

    if (!userDoc.exists) {
      return res.status(404).json({ error: 'Usuario no encontrado' });
    }

    res.json({
      success: true,
      data: { id: userId, ...userDoc.data() }
    });
  } catch (error) {
    res.status(401).json({ error: 'Token inválido' });
  }
});

Desplegar:

firebase deploy --only functions:getUserProfile

Llamar desde el cliente:

async function getUserProfile(token) {
  const response = await fetch(
    'https://us-central1-tu-app.cloudfunctions.net/getUserProfile',
    {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    }
  );

  const data = await response.json();
  return data;
}

Disparadores de Base de Datos

const { onDocumentWritten } = require('firebase-functions/v2/firestore');

// Disparar cuando el documento de usuario cambia
exports.onUserUpdate = onDocumentWritten(
  'users/{userId}',
  async (event) => {
    const userId = event.params.userId;
    const before = event.data?.before?.data();
    const after = event.data?.after?.data();

    // Verificar si el correo electrónico cambió
    if (before?.email !== after?.email) {
      console.log(`El correo electrónico del usuario ${userId} cambió: ${before?.email} → ${after?.email}`);

      // Enviar correo electrónico de notificación
      await admin.auth().getUser(userId);
      // Agrega tu lógica de correo electrónico aquí
    }
  }
);

// Disparar en la creación de una nueva publicación
exports.onNewPost = onDocumentWritten(
  'posts/{postId}',
  async (event) => {
    const post = event.data?.after?.data();

    if (!post) return; // Documento eliminado

    // Verificar si es un nuevo documento
    if (!event.data?.before?.exists) {
      console.log('Nueva publicación creada:', post.title);

      // Notificar a los seguidores
      const followersSnap = await admin.firestore()
        .collection('users')
        .where('following', 'array-contains', post.authorId)
        .get();

      const notifications = followersSnap.docs.map(doc => ({
        userId: doc.id,
        postId: event.params.postId,
        type: 'new_post',
        createdAt: admin.firestore.FieldValue.serverTimestamp()
      }));

      const batch = admin.firestore().batch();
      notifications.forEach(notif => {
        const ref = admin.firestore().collection('notifications').doc();
        batch.set(ref, notif);
      });

      await batch.commit();
    }
  }
);

Funciones Programadas (Trabajos Cron)

const { onSchedule } = require('firebase-functions/v2/scheduler');

// Ejecutar cada día a medianoche UTC
exports.dailyCleanup = onSchedule('every 24 hours', async (event) => {
  console.log('Ejecutando limpieza diaria');

  // Eliminar notificaciones antiguas (más de 30 días)
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  const oldNotifs = await admin.firestore()
    .collection('notifications')
    .where('createdAt', '<', thirtyDaysAgo)
    .get();

  const batch = admin.firestore().batch();
  oldNotifs.forEach(doc => batch.delete(doc.ref));
  await batch.commit();

  console.log(`Eliminadas ${oldNotifs.size} notificaciones antiguas`);
});

Configuración de Entorno

# Establecer variables de entorno
firebase functions:config:set \
  stripe.secret="sk_test_xxx" \
  email.api_key="key_xxx"

# Acceder en funciones
const config = require('firebase-functions/config');
const stripe = require('stripe')(config.stripe.secret);

Cloud Storage: Carga y Gestión de Archivos

Almacena cargas de usuarios, imágenes y archivos con distribución automática de CDN.

Configurar Reglas de Almacenamiento

// Consola de Firebase > Storage > Reglas
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {

    // Carpeta de cargas de usuario
    match /users/{userId}/{allPaths=**} {
      allow read: if true; // Lectura pública
      allow write: if request.auth.uid == userId;
      allow delete: if request.auth.uid == userId;
    }

    // Activos públicos
    match /public/{allPaths=**} {
      allow read: if true;
      allow write: if false; // Solo administrador vía Consola de Firebase
    }
  }
}

Cargar Archivos (Cliente)

import {
  getStorage,
  ref,
  uploadBytesResumable,
  getDownloadURL
} from 'firebase/storage';

const storage = getStorage(app);

async function uploadProfileImage(userId, file) {
  // Crear referencia de almacenamiento
  const storageRef = ref(storage, `users/${userId}/profile/${file.name}`);

  // Cargar archivo
  const uploadTask = uploadBytesResumable(storageRef, file);

  return new Promise((resolve, reject) => {
    uploadTask.on(
      'state_changed',
      (snapshot) => {
        // Rastrear progreso
        const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        console.log(`Carga: ${progress.toFixed(0)}%`);
      },
      (error) => {
        // Manejar errores
        switch (error.code) {
          case 'storage/unauthorized':
            reject(new Error('No tienes permiso'));
            break;
          case 'storage/canceled':
            reject(new Error('Carga cancelada'));
            break;
          default:
            reject(new Error('Fallo la carga'));
        }
      },
      async () => {
        // Carga completada
        const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
        console.log('Archivo disponible en:', downloadURL);
        resolve(downloadURL);
      }
    );
  });
}

// Uso
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];

if (file) {
  const imageUrl = await uploadProfileImage(auth.currentUser.uid, file);

  // Guardar URL en Firestore
  await updateDoc(doc(db, 'users', auth.currentUser.uid), {
    profileImage: imageUrl
  });
}

Descargar Archivos

import { getDownloadURL } from 'firebase/storage';

async function getProfileImage(userId) {
  const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);

  try {
    const url = await getDownloadURL(imageRef);
    return url;
  } catch (error) {
    if (error.code === 'storage/object-not-found') {
      return null; // No hay imagen de perfil
    }
    throw error;
  }
}

Eliminar Archivos

import { deleteObject } from 'firebase/storage';

async function deleteProfileImage(userId) {
  const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);
  await deleteObject(imageRef);
  console.log('Imagen de perfil eliminada');
}

Probando APIs de Firebase con Apidog

Firebase proporciona APIs REST para todos los servicios. Probarlos directamente ayuda a depurar problemas y entender las solicitudes subyacentes.

Importar API REST de Firebase

  1. Abrir Apidog
  2. Crear nuevo proyecto: "Firebase API"
  3. Importar especificación OpenAPI de la documentación de Firebase
  4. O añadir puntos finales manualmente:

Punto Final REST de Firestore:

POST https://firestore.googleapis.com/v1/projects/{projectId}/databases/(default)/documents
Authorization: Bearer {oauth2_token}
Content-Type: application/json

{
  "fields": {
    "name": { "stringValue": "John" },
    "email": { "stringValue": "john@example.com" },
    "age": { "integerValue": 30 }
  }
}

Punto Final de Autenticación:

POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={api_key}
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "secret123",
  "returnSecureToken": true
}

Probar Flujo de Autenticación

  1. Crear solicitud: "Iniciar Sesión"
  2. Establecer método: POST
  3. Agregar correo electrónico/contraseña en el cuerpo
  4. Guardar token de respuesta como variable de entorno
  5. Usar {{token}} en solicitudes posteriores

Depurar Reglas de Seguridad

Usa Firebase Emulator Suite para pruebas locales:

# Iniciar emulador
firebase emulators:start

# Probar contra Firestore local
# http://localhost:8080

Mejores Prácticas de Producción

1. Implementar un Manejo Adecuado de Errores

// Lógica de reintento para fallos transitorios
async function firestoreWithRetry(operation, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await operation();
    } catch (error) {
      if (
        error.code === 'unavailable' ||
        error.code === 'deadline-exceeded'
      ) {
        const delay = Math.pow(2, i) * 1000; // Retroceso exponencial
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
}

2. Optimizar el Rendimiento de las Consultas

Agrega índices compuestos para consultas de múltiples campos:

// Esta consulta necesita un índice compuesto
const q = query(
  collection(db, 'posts'),
  where('category', '==', 'tech'),
  where('views', '>', 1000),
  orderBy('views', 'desc')
);

Firestore te indica que crees el índice con un enlace directo cuando ejecutas esta consulta.

3. Operaciones por Lotes

import { writeBatch } from 'firebase/firestore';

async function bulkUpdate(userIds, updates) {
  const batch = writeBatch(db);

  userIds.forEach(id => {
    const ref = doc(db, 'users', id);
    batch.update(ref, updates);
  });

  await batch.commit();
  console.log(`Actualizados ${userIds.length} usuarios`);
}

// Máximo 500 operaciones por lote

4. Monitorear Costos

Precios de Firebase:

Servicio Nivel Gratuito De Pago
Firestore 50K lecturas/día $0.036/100K lecturas
Storage 5GB $0.023/GB
Functions 2M invocaciones $0.40/1M
Auth 10K/mes $0.0055/100K

Configura alertas de presupuesto en la Consola de Google Cloud.

5. Proteger Cuentas de Servicio

// MAL: Nunca hagas esto en el código del cliente
admin.initializeApp({
  credential: admin.credential.cert(require('./serviceAccountKey.json'))
});

// CORRECTO: Usar solo en entornos de servidor
const serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

6. Manejar Escenarios Sin Conexión

// Habilitar persistencia sin conexión (web)
import { enableMultiTabIndexedDbPersistence } from 'firebase/firestore';

enableMultiTabIndexedDbPersistence(db)
  .catch((err) => {
    if (err.code === 'failed-precondition') {
      // Múltiples pestañas abiertas
    } else if (err.code === 'unimplemented') {
      // El navegador no es compatible
    }
  });

// Escuchar conectividad
import { onSnapshot } from 'firebase/firestore';

onSnapshot(doc(db, 'status', 'online'), (doc) => {
  if (!doc.exists()) {
    console.log('Estás sin conexión');
    // Mostrar interfaz de usuario sin conexión
  }
});

Problemas Comunes de la API de Firebase y Soluciones

Problema 1: Errores de Permiso Denegado

Síntoma: Error: 7 PERMISSION_DENIED

Causa: Las reglas de seguridad bloquean la operación

Solución:

  1. Verifica las reglas en la Consola de Firebase
  2. Verifica que request.auth.uid coincida con el usuario esperado
  3. Prueba las reglas con el Rules Playground

Problema 2: Expiración del Token

Síntoma: Error: ID token expired

Solución:

// Forzar actualización del token
const user = auth.currentUser;
if (user) {
  await user.getIdToken(true); // Forzar actualización
}

Problema 3: Latencia de Inicio en Frío

Síntoma: Las Cloud Functions tardan de 2 a 5 segundos en la primera llamada

Solución:

// Mantener las funciones "calientes" con pings programados
exports.keepWarm = onSchedule('every 60 seconds', async () => {
  await fetch('https://tu-funcion.cloudfunctions.net/health');
});

Problema 4: Consulta Devuelve Resultados Vacíos

Síntoma: La consulta debería devolver datos pero devuelve un array vacío

Causa: Índice faltante o orden de campos incorrecto

Solución: Revisa la Consola de Firestore > Índices para los índices compuestos requeridos.

Casos de Uso en el Mundo Real

Aplicación Fintech: Actualizaciones de Transacciones en Tiempo Real

Una startup de pagos utilizó Firebase Firestore para construir notificaciones de transacciones en tiempo real. Cuando se procesa un pago, las Cloud Functions activan actualizaciones en todos los paneles de administración conectados en 200 ms. Resultado: una reducción del 40% en los tickets de soporte sobre transacciones "pendientes".

Comercio Electrónico: Sincronización de Inventario

Un minorista en línea sincroniza el inventario en la web, iOS y Android utilizando escuchas de Firestore. Cuando el stock cambia, todos los clientes se actualizan automáticamente. La persistencia sin conexión garantiza que los trabajadores del almacén puedan escanear artículos sin conectividad, con sincronización automática al reconectarse.

SaaS: Autenticación Multitenant

Una plataforma B2B utiliza Firebase Auth con reclamaciones personalizadas para el acceso basado en roles. Los usuarios administradores obtienen permisos elevados a través de Cloud Functions que validan contra las configuraciones de tenant de Firestore. Una única base de código sirve a más de 500 organizaciones con datos aislados.

Conclusión

La integración de la API de Firebase implica cuatro servicios principales:

Has aprendido flujos de autenticación, operaciones de base de datos, despliegue de funciones y gestión de archivos. Has visto patrones de producción: manejo de errores, procesamiento por lotes, soporte sin conexión y seguridad.

button

Preguntas Frecuentes

¿Es Firebase de uso gratuito?

Sí, Firebase tiene un generoso nivel gratuito (Plan Spark) que incluye 5 GB de almacenamiento, 50K lecturas de Firestore al día, 2M invocaciones de Cloud Function y 10K usuarios de Auth al mes. Los planes de pago (Blaze) utilizan precios de pago por uso.

¿Puedo usar Firebase con bases de datos existentes?

Sí. Usa Firebase Extensions para sincronizar con PostgreSQL, MySQL o MongoDB. O llama a APIs externas desde Cloud Functions para integrar con sistemas existentes.

¿Cómo migro de Firebase a otra plataforma?

Exporta datos usando las funciones de exportación de Firestore o la CLI de Firebase. Para grandes conjuntos de datos, usa la tubería de exportación de Dataflow. La complejidad de la migración depende de tu estructura de datos.

¿Firebase soporta GraphQL?

No de forma nativa. Usa soluciones de terceros como firestore-graphql o construye una capa GraphQL con Cloud Functions y Apollo Server.

¿Puedo usar Firebase on-premise?

No. Firebase es solo para Google Cloud. Para alternativas autoalojadas, considera Appwrite, Supabase o Nhost.

¿Cómo manejo cargas de archivos de más de 100 MB?

Usa cargas reanudables con fragmentación. El SDK de Firebase lo maneja automáticamente. Para archivos muy grandes, usa Google Cloud Storage directamente con URLs firmadas.

¿Qué sucede si excedo los límites de consulta de Firestore?

Las consultas fallan con el error FAILED_PRECONDITION. Agrega los índices requeridos o reestructura las consultas. Firestore proporciona enlaces directos para crear los índices faltantes en el mensaje de error.

¿Firebase cumple con el GDPR?

Sí, Firebase ofrece procesamiento de datos compatible con el GDPR. Habilita la residencia de datos en regiones específicas, implementa la exportación/eliminación de datos de usuario y firma la Enmienda de Procesamiento de Datos de Google.

Practica el diseño de API en Apidog

Descubre una forma más fácil de construir y usar APIs