Você está construindo um aplicativo. Usuários precisam fazer login. Dados precisam sincronizar em tempo real. Arquivos precisam de armazenamento. Você poderia provisionar servidores, configurar bancos de dados e gerenciar infraestrutura por semanas. Ou você poderia usar o Firebase.
O Firebase impulsiona mais de 1,5 milhão de aplicativos, incluindo The New York Times, Duolingo e Alibaba. Desenvolvedores o escolhem porque ele remove a complexidade do backend. Você se concentra nos recursos, não na manutenção do servidor. Mas a API do Firebase tem suas particularidades. Fluxos de autenticação confundem iniciantes. Regras de banco de dados atrapalham desenvolvedores experientes. Cloud Functions parecem mágicas até que você entenda os gatilhos.
Eu integrei o Firebase em aplicativos de produção que atendem milhões de usuários. Cometi todos os erros possíveis: chaves de conta de serviço expostas, consultas ineficientes, funções quebradas implantadas. Este guia destila essas lições.
Você aprenderá autenticação, operações de banco de dados, Cloud Functions e armazenamento. Você verá código funcionando, não apenas teoria. Você evitará as armadilhas que causam problemas em produção.
O Que É a API do Firebase e Por Que Ela Importa?
Firebase não é uma única API. É um conjunto de serviços de backend acessados por meio de SDKs unificados e endpoints REST.
Principais Serviços do Firebase
| Serviço | Propósito | Tipo de API |
|---|---|---|
| Authentication | Login e identidade do usuário | SDK + REST |
| Firestore Database | Banco de dados de documentos NoSQL | SDK + REST |
| Realtime Database | Sincronização JSON em tempo real | SDK + REST |
| Cloud Storage | Armazenamento de arquivos e CDN | SDK + REST |
| Cloud Functions | Computação sem servidor | CLI de Implantação |
| Hosting | Hospedagem web estática | CLI de Implantação |
| Cloud Messaging | Notificações push | API HTTP v1 |
Quando o Firebase Faz Sentido
O Firebase resolve problemas específicos muito bem:
Use o Firebase quando:
- Você precisa de sincronização em tempo real (chat, colaboração, atualizações ao vivo)
- Você deseja arquitetura sem servidor (sem gerenciamento de infraestrutura)
- Você está construindo aplicativos móveis ou web (SDKs lidam com diferenças de plataforma)
- Você precisa de suporte offline (SDKs armazenam dados em cache automaticamente)
- Você deseja autenticação integrada (login com Google, Apple, e-mail, telefone)
Pule o Firebase quando:
- Você precisa de consultas relacionais complexas (use PostgreSQL em vez disso)
- Você tem requisitos rigorosos de residência de dados (as regiões do Firebase são limitadas)
- Você precisa de recursos SQL completos (existem limitações de consulta no Firestore)
- O custo em escala importa mais do que a velocidade de desenvolvimento (auto-hospedagem é mais barata)
A Arquitetura da API do Firebase
O Firebase usa uma abordagem híbrida:
┌─────────────────────────────────────────────────────────┐
│ Sua Aplicação │
├─────────────────────────────────────────────────────────┤
│ Firebase SDK (Cliente) │
│ - Gerencia tokens de autenticação automaticamente │
│ - Gerencia cache offline │
│ - Listeners em tempo real │
└─────────────────────────────────────────────────────────┘
│
│ HTTPS + WebSocket
▼
┌─────────────────────────────────────────────────────────┐
│ Backend do Firebase │
├──────────────┬──────────────┬──────────────┬────────────┤
│ Serviço │ Banco de │ Serviço │ Runtime de │
│ de Auth │ Dados │ de Armaz. │ Funções │
│ │ (Firestore) │ │ │
└──────────────┴──────────────┴──────────────┴────────────┘
Os SDKs do cliente abstraem a camada HTTP. Por baixo, cada operação se traduz em chamadas de API REST com autenticação JWT.
Autenticação Firebase: Configuração Completa
A autenticação é sua primeira integração com o Firebase. Se você errar isso, todo o resto falhará.
Passo 1: Criar Projeto Firebase
- Vá para o Console do Firebase

Clique em “Adicionar projeto” e Digite o nome do projeto (sem espaços)

Ative o Google Analytics (opcional, mas recomendado)

Clique em “Criar projeto”

Aguarde 30 segundos para o provisionamento. Você verá o painel do projeto.
Passo 2: Registrar Seu Aplicativo
Para Aplicativos Web:
// No Console do Firebase > Configurações do Projeto > Geral
// Clique em "Adicionar aplicativo" > Ícone da Web
// Registrar aplicativo web
const firebaseConfig = {
apiKey: "AIzaSyDxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "seu-app.firebaseapp.com",
projectId: "seu-app",
storageBucket: "seu-app.appspot.com",
messagingSenderId: "123456789012",
appId: "1:123456789012:web:abc123def456"
};
// Inicializar Firebase
import { initializeApp } from 'firebase/app';
const app = initializeApp(firebaseConfig);
Para Aplicativos iOS:
Baixe GoogleService-Info.plist e adicione ao projeto Xcode. Certifique-se de que "Target Membership" inclua seu aplicativo.
Para Aplicativos Android:
Baixe google-services.json e coloque no diretório app/. Adicione ao build.gradle:
// build.gradle de nível de projeto
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
}
// build.gradle de nível de aplicativo
plugins {
id 'com.google.gms.google-services'
}
Passo 3: Ativar Métodos de Autenticação
No Console do Firebase > Authentication > Método de login:
- E-mail/Senha: Ativar para registro tradicional
- Google: Adicione sua impressão digital do certificado SHA-1 (Android) ou ID do pacote (iOS)
- Apple: Necessário para aplicativos iOS se você ativar qualquer login social
- Telefone: Ativar para autenticação por SMS (requer faturamento)
Passo 4: Implementar o Fluxo de Autenticação
Cadastro com E-mail/Senha:
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
);
// Definir nome de exibição
await updateProfile(userCredential.user, {
displayName: displayName
});
console.log('Usuário criado:', userCredential.user.uid);
return userCredential.user;
} catch (error) {
// Lidar com códigos de erro específicos
switch (error.code) {
case 'auth/email-already-in-use':
throw new Error('Este e-mail já está registrado');
case 'auth/weak-password':
throw new Error('A senha deve ter pelo menos 6 caracteres');
case 'auth/invalid-email':
throw new Error('Endereço de e-mail inválido');
default:
throw new Error('Falha no cadastro: ' + error.message);
}
}
}
Login com E-mail/Senha:
import {
signInWithEmailAndPassword,
signOut
} from 'firebase/auth';
async function signIn(email, password) {
try {
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
const user = userCredential.user;
// Obter token de ID para chamadas de API
const idToken = await user.getIdToken();
console.log('Token de autenticação:', idToken);
return user;
} catch (error) {
switch (error.code) {
case 'auth/user-not-found':
throw new Error('Nenhuma conta com este e-mail');
case 'auth/wrong-password':
throw new Error('Senha incorreta');
case 'auth/too-many-requests':
throw new Error('Muitas tentativas. Tente novamente mais tarde');
default:
throw new Error('Falha no login');
}
}
}
async function logOut() {
await signOut(auth);
console.log('Usuário desconectado');
}
Login com Google (Web):
import {
GoogleAuthProvider,
signInWithPopup
} from 'firebase/auth';
async function signInWithGoogle() {
const provider = new GoogleAuthProvider();
// Solicitar escopos adicionais
provider.addScope('email');
provider.addScope('profile');
try {
const result = await signInWithPopup(auth, provider);
const user = result.user;
// Acessar token OAuth do 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('Login cancelado');
}
throw new Error('Falha no login com Google');
}
}
Passo 5: Proteger Rotas com o Estado de Autenticação
import { onAuthStateChanged } from 'firebase/auth';
// Inscrever-se para alterações no estado de autenticação
onAuthStateChanged(auth, (user) => {
if (user) {
// Usuário está logado
console.log('Usuário:', user.email);
// Redirecionar para o painel
window.location.href = '/dashboard';
} else {
// Usuário está desconectado
console.log('Nenhum usuário');
// Redirecionar para o login
window.location.href = '/login';
}
});
Erros Comuns de Autenticação
Erro 1: Não lidar com a atualização de token
O SDK do Firebase atualiza automaticamente os tokens. Mas se você armazenar tokens em cache no lado do servidor, eles expirarão após 1 hora. Sempre verifique os tokens em cada solicitação ou implemente uma lógica de atualização.
Erro 2: Expor credenciais de administrador no código do cliente
Nunca use chaves de conta de serviço em aplicativos cliente. As contas de serviço ignoram as regras de segurança. Use-as apenas em ambientes de servidor confiáveis.
Erro 3: Pular a verificação de e-mail
import { sendEmailVerification } from 'firebase/auth';
async function sendVerificationEmail(user) {
await sendEmailVerification(user);
console.log('E-mail de verificação enviado');
}
// Verificar status da verificação
if (!auth.currentUser.emailVerified) {
console.log('E-mail não verificado');
// Restringir acesso
}
Firestore Database: Operações e Consultas
Firestore é o banco de dados NoSQL do Firebase. Documentos são organizados em coleções. As consultas escalam automaticamente.
Estrutura de Dados
seu-projeto (raiz)
└── users (coleção)
├── userId123 (documento)
│ ├── name: "John"
│ ├── email: "john@example.com"
│ └── posts (subcoleção)
│ ├── postId1 (documento)
│ └── postId2 (documento)
└── userId456 (documento)
Inicializar Firestore
import { getFirestore } from 'firebase/firestore';
const db = getFirestore(app);
Criar Documentos
import {
collection,
addDoc,
setDoc,
doc
} from 'firebase/firestore';
// Opção 1: ID auto-gerado
async function createUser(userData) {
const docRef = await addDoc(collection(db, 'users'), userData);
console.log('Documento escrito com ID:', docRef.id);
return docRef.id;
}
// Opção 2: ID personalizado
async function createUserWithId(userId, userData) {
await setDoc(doc(db, 'users', userId), userData);
console.log('Documento escrito com ID personalizado:', userId);
}
// Uso
const userId = await createUser({
name: 'Alice',
email: 'alice@example.com',
createdAt: new Date(),
role: 'user'
});
Ler Documentos
import {
getDoc,
getDocs,
query,
where,
orderBy,
limit
} from 'firebase/firestore';
// Obter documento único
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('Usuário não encontrado');
}
}
// Consulta com 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('Usuários administradores:', adminUsers);
Atualizar Documentos
import {
updateDoc,
increment,
arrayUnion,
arrayRemove
} from 'firebase/firestore';
async function updateUser(userId, updates) {
const userRef = doc(db, 'users', userId);
await updateDoc(userRef, updates);
}
// Operações atômicas
await updateUser('userId123', {
loginCount: increment(1),
tags: arrayUnion('premium', 'beta-tester'),
lastLogin: new Date()
});
// Remover do array
await updateUser('userId123', {
tags: arrayRemove('beta-tester')
});
Excluir Documentos
import { deleteDoc } from 'firebase/firestore';
async function deleteUser(userId) {
await deleteDoc(doc(db, 'users', userId));
console.log('Usuário excluído');
}
Listeners em Tempo Real
import { onSnapshot } from 'firebase/firestore';
// Escutar um único documento
const unsubscribe = onSnapshot(
doc(db, 'users', userId),
(doc) => {
console.log('Usuário atualizado:', doc.data());
},
(error) => {
console.error('Erro ao escutar:', error);
}
);
// Escutar 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('Posts publicados:', posts);
});
// Parar de escutar
unsubscribe();
unsubscribeQuery();
Regras de Segurança do Firestore
Sem as regras adequadas, qualquer pessoa pode ler seus dados. Defina as regras no Console do Firebase > Firestore > Rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Função auxiliar
function isAuthenticated() {
return request.auth != null;
}
function isOwner(userId) {
return request.auth.uid == userId;
}
// Coleção de usuários
match /users/{userId} {
allow read: if isAuthenticated();
allow create: if isAuthenticated() && isOwner(userId);
allow update, delete: if isOwner(userId);
}
// Coleção de posts
match /posts/{postId} {
allow read: if true; // Leitura pública
allow create: if isAuthenticated();
allow update, delete: if resource.data.authorId == request.auth.uid;
}
// Subcoleção privada
match /users/{userId}/private/{document} {
allow read, write: if isOwner(userId);
}
}
}
Limitações de Consulta
O Firestore tem restrições:
- Sem consultas OR (use `in` com array ou múltiplas consultas)
- Sem pesquisas com curinga (use Algolia ou Meilisearch para texto completo)
- Consultas compostas precisam de índices (Firestore cria automaticamente índices de campo único)
- Limite de 30 disjunções em consultas `in`
Solução alternativa para consultas OR:
// Em vez 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)
]);
// Mesclar resultados no cliente
Cloud Functions: Lógica de Backend sem Servidor
Cloud Functions executam código de backend sem gerenciar servidores. Disparam em mudanças de banco de dados, requisições HTTP ou eventos agendados.
Configuração
# Instalar Firebase CLI
npm install -g firebase-tools
# Login
firebase login
# Inicializar funções em seu projeto
firebase init functions
# Selecione: JavaScript, ESLint sim, Express.js não
Funções HTTP (Endpoints de API)
// functions/index.js
const { onRequest } = require('firebase-functions/v2/https');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
// Endpoint 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 });
}
});
// Endpoint protegido (verifica token de autenticação)
exports.getUserProfile = onRequest(async (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
// Obter token do cabeçalho Authorization
const authHeader = req.headers.authorization || '';
const token = authHeader.split('Bearer ')[1];
if (!token) {
return res.status(401).json({ error: 'Não autorizado' });
}
try {
// Verificar token
const decodedToken = await admin.auth().verifyIdToken(token);
const userId = decodedToken.uid;
// Obter dados do usuário
const userDoc = await db.collection('users').doc(userId).get();
if (!userDoc.exists) {
return res.status(404).json({ error: 'Usuário não encontrado' });
}
res.json({
success: true,
data: { id: userId, ...userDoc.data() }
});
} catch (error) {
res.status(401).json({ error: 'Token inválido' });
}
});
Implantar:
firebase deploy --only functions:getUserProfile
Chamar do cliente:
async function getUserProfile(token) {
const response = await fetch(
'https://us-central1-your-app.cloudfunctions.net/getUserProfile',
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
const data = await response.json();
return data;
}
Gatilhos de Banco de Dados
const { onDocumentWritten } = require('firebase-functions/v2/firestore');
// Disparar quando o documento do usuário muda
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 se o e-mail mudou
if (before?.email !== after?.email) {
console.log(`E-mail do usuário ${userId} mudou: ${before?.email} → ${after?.email}`);
// Enviar e-mail de notificação
await admin.auth().getUser(userId);
// Adicione sua lógica de e-mail aqui
}
}
);
// Disparar na criação de um novo post
exports.onNewPost = onDocumentWritten(
'posts/{postId}',
async (event) => {
const post = event.data?.after?.data();
if (!post) return; // Documento excluído
// Verificar se é um novo documento
if (!event.data?.before?.exists) {
console.log('Novo post criado:', post.title);
// Notificar 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();
}
}
);
Funções Agendadas (Tarefas Cron)
const { onSchedule } = require('firebase-functions/v2/scheduler');
// Executar todo dia à meia-noite UTC
exports.dailyCleanup = onSchedule('every 24 hours', async (event) => {
console.log('Executando limpeza diária');
// Excluir notificações antigas (mais de 30 dias)
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(`Excluídas ${oldNotifs.size} notificações antigas`);
});
Configuração de Ambiente
# Definir variáveis de ambiente
firebase functions:config:set \
stripe.secret="sk_test_xxx" \
email.api_key="key_xxx"
# Acessar nas funções
const config = require('firebase-functions/config');
const stripe = require('stripe')(config.stripe.secret);
Cloud Storage: Upload e Gerenciamento de Arquivos
Armazene uploads de usuários, imagens e arquivos com distribuição CDN automática.
Configurar Regras de Armazenamento
// Console do Firebase > Storage > Regras
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// Pasta de uploads de usuários
match /users/{userId}/{allPaths=**} {
allow read: if true; // Leitura pública
allow write: if request.auth.uid == userId;
allow delete: if request.auth.uid == userId;
}
// Ativos públicos
match /public/{allPaths=**} {
allow read: if true;
allow write: if false; // Somente Admin via Console do Firebase
}
}
}
Fazer Upload de Arquivos (Cliente)
import {
getStorage,
ref,
uploadBytesResumable,
getDownloadURL
} from 'firebase/storage';
const storage = getStorage(app);
async function uploadProfileImage(userId, file) {
// Criar referência de armazenamento
const storageRef = ref(storage, `users/${userId}/profile/${file.name}`);
// Fazer upload do arquivo
const uploadTask = uploadBytesResumable(storageRef, file);
return new Promise((resolve, reject) => {
uploadTask.on(
'state_changed',
(snapshot) => {
// Acompanhar progresso
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(`Upload: ${progress.toFixed(0)}%`);
},
(error) => {
// Lidar com erros
switch (error.code) {
case 'storage/unauthorized':
reject(new Error('Você não tem permissão'));
break;
case 'storage/canceled':
reject(new Error('Upload cancelado'));
break;
default:
reject(new Error('Falha no upload'));
}
},
async () => {
// Upload concluído
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
console.log('Arquivo disponível em:', 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);
// Salvar URL no Firestore
await updateDoc(doc(db, 'users', auth.currentUser.uid), {
profileImage: imageUrl
});
}
Baixar Arquivos
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; // Nenhuma imagem de perfil
}
throw error;
}
}
Excluir Arquivos
import { deleteObject } from 'firebase/storage';
async function deleteProfileImage(userId) {
const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);
await deleteObject(imageRef);
console.log('Imagem de perfil excluída');
}
Testando APIs Firebase com Apidog
O Firebase fornece APIs REST para todos os serviços. Testá-las diretamente ajuda a depurar problemas e a entender as requisições subjacentes.
Importar API REST do Firebase
- Abra o Apidog
- Crie um novo projeto: "Firebase API"
- Importe a especificação OpenAPI da documentação do Firebase
- Ou adicione endpoints manualmente:
Endpoint REST do 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 }
}
}
Endpoint de Autenticação:
POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={api_key}
Content-Type: application/json
{
"email": "user@example.com",
"password": "secret123",
"returnSecureToken": true
}
Testar Fluxo de Autenticação
- Crie a requisição: "Login"
- Defina o método: POST
- Adicione e-mail/senha no corpo
- Salve o token de resposta como variável de ambiente
- Use
{{token}}nas requisições subsequentes
Depurar Regras de Segurança
Use a Firebase Emulator Suite para testes locais:
# Iniciar emulador
firebase emulators:start
# Testar contra Firestore local
# http://localhost:8080
Melhores Práticas em Produção
1. Implementar Tratamento de Erros Adequado
// Lógica de reintetativa para falhas transientes
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; // Backoff exponencial
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}
2. Otimizar o Desempenho das Consultas
Adicione índices compostos para consultas multi-campo:
// Esta consulta precisa de um índice composto
const q = query(
collection(db, 'posts'),
where('category', '==', 'tech'),
where('views', '>', 1000),
orderBy('views', 'desc')
);
O Firestore o orientará a criar o índice com um link direto quando você executar esta consulta.
3. Operações em Lote
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(`Atualizados ${userIds.length} usuários`);
}
// Máximo de 500 operações por lote
4. Monitorar Custos
Preços do Firebase:
| Serviço | Nível Gratuito | Pago |
|---|---|---|
| Firestore | 50K leituras/dia | $0.036/100K leituras |
| Storage | 5GB | $0.023/GB |
| Functions | 2M invocações | $0.40/1M |
| Auth | 10K/mês | $0.0055/100K |
Defina alertas de orçamento no Google Cloud Console.
5. Proteger Contas de Serviço
// ERRADO: Nunca faça isso no código do cliente
admin.initializeApp({
credential: admin.credential.cert(require('./serviceAccountKey.json'))
});
// CORRETO: Use apenas em ambiente de servidor
const serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
6. Lidar com Cenários Offline
// Ativar persistência offline (web)
import { enableMultiTabIndexedDbPersistence } from 'firebase/firestore';
enableMultiTabIndexedDbPersistence(db)
.catch((err) => {
if (err.code === 'failed-precondition') {
// Múltiplas abas abertas
} else if (err.code === 'unimplemented') {
// Navegador não suporta
}
});
// Escutar conectividade
import { onSnapshot } from 'firebase/firestore';
onSnapshot(doc(db, 'status', 'online'), (doc) => {
if (!doc.exists()) {
console.log('Você está offline');
// Mostrar UI offline
}
});
Problemas Comuns da API Firebase e Soluções
Problema 1: Erros de Permissão Negada
Sintoma: Error: 7 PERMISSION_DENIED
Causa: As regras de segurança bloqueiam a operação
Correção:
- Verifique as regras no Console do Firebase
- Verifique se
request.auth.uidcorresponde ao usuário esperado - Teste as regras com o Rules Playground
Problema 2: Expiração de Token
Sintoma: Error: ID token expired
Correção:
// Forçar atualização de token
const user = auth.currentUser;
if (user) {
await user.getIdToken(true); // Forçar atualização
}
Problema 3: Latência de Cold Start
Sintoma: Cloud Functions levam de 2 a 5 segundos na primeira chamada
Correção:
// Manter as funções "quentes" com pings agendados
exports.keepWarm = onSchedule('every 60 seconds', async () => {
await fetch('https://your-function.cloudfunctions.net/health');
});
Problema 4: Consulta Retorna Resultados Vazios
Sintoma: A consulta deveria retornar dados, mas retorna um array vazio
Causa: Índice ausente ou ordem de campo incorreta
Correção: Verifique o Console do Firestore > Índices para os índices compostos necessários.
Casos de Uso no Mundo Real
App Fintech: Atualizações de Transações em Tempo Real
Uma startup de pagamentos usou o Firebase Firestore para criar notificações de transações em tempo real. Quando um pagamento é processado, o Cloud Functions aciona atualizações para todos os painéis administrativos conectados em 200ms. Resultado: 40% de redução nos tickets de suporte sobre transações "pendentes".
E-commerce: Sincronização de Estoque
Um varejista online sincroniza o estoque em web, iOS e Android usando listeners do Firestore. Quando o estoque muda, todos os clientes são atualizados automaticamente. A persistência offline garante que os trabalhadores do armazém possam escanear itens sem conectividade, com sincronização automática quando reconectados.
SaaS: Autenticação Multi-Tenant
Uma plataforma B2B usa Firebase Auth com custom claims para acesso baseado em funções. Usuários administradores obtêm permissões elevadas via Cloud Functions que validam contra as configurações de tenant do Firestore. Uma única base de código atende mais de 500 organizações com dados isolados.
Conclusão
A integração da API Firebase envolve quatro serviços principais:
- Autenticação: Login com e-mail, Google, Apple com tokens JWT
- Firestore: Banco de dados NoSQL com listeners em tempo real e regras de segurança
- Cloud Functions: Backend sem servidor acionado por eventos ou HTTP
- Storage: Upload de arquivos com distribuição CDN
Você aprendeu fluxos de autenticação, operações de banco de dados, implantação de funções e gerenciamento de arquivos. Você viu padrões de produção: tratamento de erros, processamento em lote, suporte offline e segurança.
FAQ
O Firebase é gratuito?
Sim, o Firebase possui um generoso nível gratuito (Plano Spark) incluindo 5GB de armazenamento, 50K leituras do Firestore por dia, 2M invocações de Cloud Functions e 10K usuários de Auth por mês. Planos pagos (Blaze) usam preços de pagamento conforme o uso.
Posso usar o Firebase com bancos de dados existentes?
Sim. Use as Extensões do Firebase para sincronizar com PostgreSQL, MySQL ou MongoDB. Ou chame APIs externas do Cloud Functions para integrar com sistemas existentes.
Como migro do Firebase para outra plataforma?
Exporte dados usando as funções de exportação do Firestore ou o Firebase CLI. Para grandes conjuntos de dados, use o pipeline de exportação do Dataflow. A complexidade da migração depende da estrutura dos seus dados.
O Firebase suporta GraphQL?
Não nativamente. Use soluções de terceiros como firestore-graphql ou construa uma camada GraphQL com Cloud Functions e Apollo Server.
Posso usar o Firebase localmente?
Não. O Firebase é exclusivamente Google Cloud. Para alternativas auto-hospedadas, considere Appwrite, Supabase ou Nhost.
Como lidar com uploads de arquivos maiores que 100MB?
Use uploads resumíveis com fragmentação (chunking). O SDK do Firebase lida com isso automaticamente. Para arquivos muito grandes, use o Google Cloud Storage diretamente com URLs assinadas.
O que acontece se eu exceder os limites de consulta do Firestore?
As consultas falham com o erro FAILED_PRECONDITION. Adicione os índices necessários ou reestruture as consultas. O Firestore fornece links diretos para criar índices ausentes na mensagem de erro.
O Firebase está em conformidade com o GDPR?
Sim, o Firebase oferece processamento de dados em conformidade com o GDPR. Habilite a residência de dados em regiões específicas, implemente a exportação/exclusão de dados do usuário e assine o Adendo de Processamento de Dados do Google.
