Vous développez une application. Les utilisateurs doivent se connecter. Les données doivent se synchroniser en temps réel. Les fichiers nécessitent un stockage. Vous pourriez déployer des serveurs, configurer des bases de données et gérer l'infrastructure pendant des semaines. Ou vous pourriez utiliser Firebase.
Essayez Apidog dès aujourd'hui
Firebase alimente plus de 1,5 million d'applications, dont The New York Times, Duolingo et Alibaba. Les développeurs le choisissent car il élimine la complexité du backend. Vous vous concentrez sur les fonctionnalités, pas sur la maintenance des serveurs. Mais l'API Firebase a ses particularités. Les flux d'authentification déroutent les débutants. Les règles de base de données piègent les développeurs expérimentés. Les fonctions Cloud semblent magiques jusqu'à ce que vous compreniez les déclencheurs.
J'ai intégré Firebase dans des applications de production servant des millions d'utilisateurs. J'ai commis toutes les erreurs possibles : exposé des clés de compte de service, écrit des requêtes inefficaces, déployé des fonctions défectueuses. Ce guide condense ces leçons.
Vous apprendrez l'authentification, les opérations de base de données, les fonctions Cloud et le stockage. Vous verrez du code fonctionnel, pas seulement de la théorie. Vous éviterez les pièges qui causent des problèmes en production.
💡Tester les API Firebase devient plus facile avec des outils clients API appropriés. Apidog vous permet d'organiser les points d'accès, de tester les flux d'authentification et de partager des collections avec votre équipe. Nous vous montrerons où il s'intègre naturellement dans le flux de travail.
Qu'est-ce que l'API Firebase et pourquoi est-elle importante ?
Firebase n'est pas une seule API. C'est une suite de services backend accessibles via des SDK unifiés et des points d'accès REST.
Services Firebase principaux
| Service | Objectif | Type d'API |
|---|---|---|
| Authentification | Connexion et identité de l'utilisateur | SDK + REST |
| Base de données Firestore | Base de données de documents NoSQL | SDK + REST |
| Base de données en temps réel | Synchronisation JSON en temps réel | SDK + REST |
| Cloud Storage | Stockage de fichiers et CDN | SDK + REST |
| Cloud Functions | Calcul sans serveur | CLI de déploiement |
| Hébergement | Hébergement web statique | CLI de déploiement |
| Cloud Messaging | Notifications push | API HTTP v1 |
Quand Firebase est pertinent
Firebase résout bien des problèmes spécifiques :
Utilisez Firebase lorsque :
- Vous avez besoin d'une synchronisation en temps réel (chat, collaboration, mises à jour en direct)
- Vous souhaitez une architecture sans serveur (pas de gestion d'infrastructure)
- Vous développez des applications mobiles ou web (les SDK gèrent les différences de plateforme)
- Vous avez besoin d'un support hors ligne (les SDK mettent automatiquement les données en cache)
- Vous souhaitez une authentification intégrée (Google, Apple, e-mail, connexion téléphonique)
Évitez Firebase lorsque :
- Vous avez besoin de requêtes relationnelles complexes (utilisez plutôt PostgreSQL)
- Vous avez des exigences strictes en matière de résidence des données (les régions Firebase sont limitées)
- Vous avez besoin de toutes les capacités SQL (des limitations de requêtes Firestore existent)
- Le coût à grande échelle est plus important que la vitesse de développement (l'auto-hébergement est moins cher)
L'architecture de l'API Firebase
Firebase utilise une approche hybride :
┌─────────────────────────────────────────────────────────┐
│ Votre application │
├─────────────────────────────────────────────────────────┤
│ SDK Firebase (Client) │
│ - Gère automatiquement les jetons d'authentification │
│ - Gère le cache hors ligne │
│ - Écouteurs en temps réel │
└─────────────────────────────────────────────────────────┘
│
│ HTTPS + WebSocket
▼
┌─────────────────────────────────────────────────────────┐
│ Backend Firebase │
├──────────────┬──────────────┬──────────────┬────────────┤
│ Service │ Base de │ Service │ Runtime │
│ d'Auth. │ données │ de Stock. │ des Fcts │
│ │ Firestore │ │ │
└──────────────┴──────────────┴──────────────┴────────────┘
Les SDK clients abstraient la couche HTTP. En arrière-plan, chaque opération se traduit par des appels d'API REST avec authentification JWT.
Authentification Firebase : Configuration complète
L'authentification est votre première intégration Firebase. Si cela échoue, tout le reste échoue.
Étape 1 : Créer un projet Firebase
- Allez à la Console Firebase
Cliquez sur "Ajouter un projet" et saisissez le nom du projet (pas d'espaces)
Activez Google Analytics (facultatif mais recommandé)
Cliquez sur "Créer le projet"
Attendez 30 secondes pour le provisionnement. Vous verrez le tableau de bord du projet.
Étape 2 : Enregistrer votre application
Pour les applications web :
// Dans la console Firebase > Paramètres du projet > Général
// Cliquez sur "Ajouter une application" > icône Web
// Enregistrer l'application web
const firebaseConfig = {
apiKey: "AIzaSyDxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "your-app.firebaseapp.com",
projectId: "your-app",
storageBucket: "your-app.appspot.com",
messagingSenderId: "123456789012",
appId: "1:123456789012:web:abc123def456"
};
// Initialiser Firebase
import { initializeApp } from 'firebase/app';
const app = initializeApp(firebaseConfig);
Pour les applications iOS :
Téléchargez GoogleService-Info.plist et ajoutez-le au projet Xcode. Assurez-vous que "Target Membership" inclut votre application.
Pour les applications Android :
Téléchargez google-services.json et placez-le dans le répertoire app/. Ajoutez à build.gradle :
// build.gradle au niveau du projet
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
}
// build.gradle au niveau de l'application
plugins {
id 'com.google.gms.google-services'
}
Étape 3 : Activer les méthodes d'authentification
Dans la console Firebase > Authentification > Méthode de connexion :
- E-mail/Mot de passe : Activez pour une inscription traditionnelle
- Google : Ajoutez votre empreinte de certificat SHA-1 (Android) ou l'ID de bundle (iOS)
- Apple : Obligatoire pour les applications iOS si vous activez une connexion sociale
- Téléphone : Activez pour l'authentification par SMS (nécessite une facturation)
Étape 4 : Implémenter le flux d'authentification
Inscription par e-mail/mot de passe :
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
);
// Définir le nom d'affichage
await updateProfile(userCredential.user, {
displayName: displayName
});
console.log('Utilisateur créé :', userCredential.user.uid);
return userCredential.user;
} catch (error) {
// Gérer les codes d'erreur spécifiques
switch (error.code) {
case 'auth/email-already-in-use':
throw new Error('Cet e-mail est déjà enregistré');
case 'auth/weak-password':
throw new Error('Le mot de passe doit contenir au moins 6 caractères');
case 'auth/invalid-email':
throw new Error('Adresse e-mail invalide');
default:
throw new Error("L'inscription a échoué : " + error.message);
}
}
}
Connexion par e-mail/mot de passe :
import {
signInWithEmailAndPassword,
signOut
} from 'firebase/auth';
async function signIn(email, password) {
try {
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
const user = userCredential.user;
// Obtenir le jeton d'identification pour les appels API
const idToken = await user.getIdToken();
console.log('Jeton d\'authentification :', idToken);
return user;
} catch (error) {
switch (error.code) {
case 'auth/user-not-found':
throw new Error('Aucun compte avec cet e-mail');
case 'auth/wrong-password':
throw new Error('Mot de passe incorrect');
case 'auth/too-many-requests':
throw new Error('Trop de tentatives. Réessayez plus tard');
default:
throw new Error('La connexion a échoué');
}
}
}
async function logOut() {
await signOut(auth);
console.log('Utilisateur déconnecté');
}
Connexion Google (Web) :
import {
GoogleAuthProvider,
signInWithPopup
} from 'firebase/auth';
async function signInWithGoogle() {
const provider = new GoogleAuthProvider();
// Demander des étendues supplémentaires
provider.addScope('email');
provider.addScope('profile');
try {
const result = await signInWithPopup(auth, provider);
const user = result.user;
// Accéder au jeton OAuth 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("Connexion annulée");
}
throw new Error('La connexion Google a échoué');
}
}
Étape 5 : Protéger les routes avec l'état d'authentification
import { onAuthStateChanged } from 'firebase/auth';
// S'abonner aux changements d'état d'authentification
onAuthStateChanged(auth, (user) => {
if (user) {
// L'utilisateur est connecté
console.log('Utilisateur :', user.email);
// Rediriger vers le tableau de bord
window.location.href = '/dashboard';
} else {
// L'utilisateur est déconnecté
console.log('Aucun utilisateur');
// Rediriger vers la page de connexion
window.location.href = '/login';
}
});
Erreurs d'authentification courantes
Erreur 1 : Ne pas gérer le rafraîchissement des jetons
Le SDK Firebase rafraîchit automatiquement les jetons. Mais si vous mettez en cache les jetons côté serveur, ils expirent après 1 heure. Vérifiez toujours les jetons à chaque requête ou implémentez une logique de rafraîchissement.
Erreur 2 : Exposer les identifiants d'administrateur dans le code client
N'utilisez jamais les clés de compte de service dans les applications clientes. Les comptes de service contournent les règles de sécurité. Utilisez-les uniquement dans des environnements serveur de confiance.
Erreur 3 : Oublier la vérification de l'e-mail
import { sendEmailVerification } from 'firebase/auth';
async function sendVerificationEmail(user) {
await sendEmailVerification(user);
console.log('E-mail de vérification envoyé');
}
// Vérifier l'état de la vérification
if (!auth.currentUser.emailVerified) {
console.log('E-mail non vérifié');
// Restreindre l'accès
}
Base de données Firestore : Opérations et requêtes
Firestore est la base de données NoSQL de Firebase. Les documents sont organisés en collections. Les requêtes s'adaptent automatiquement.
Structure des données
votre-projet (racine)
└── utilisateurs (collection)
├── userId123 (document)
│ ├── nom: "Jean"
│ ├── email: "jean@example.com"
│ └── publications (sous-collection)
│ ├── postId1 (document)
│ └── postId2 (document)
└── userId456 (document)
Initialiser Firestore
import { getFirestore } from 'firebase/firestore';
const db = getFirestore(app);
Créer des documents
import {
collection,
addDoc,
setDoc,
doc
} from 'firebase/firestore';
// Option 1 : ID auto-généré
async function createUser(userData) {
const docRef = await addDoc(collection(db, 'users'), userData);
console.log('Document écrit avec l\'ID :', docRef.id);
return docRef.id;
}
// Option 2 : ID personnalisé
async function createUserWithId(userId, userData) {
await setDoc(doc(db, 'users', userId), userData);
console.log('Document écrit avec l\'ID personnalisé :', userId);
}
// Utilisation
const userId = await createUser({
name: 'Alice',
email: 'alice@example.com',
createdAt: new Date(),
role: 'user'
});
Lire des documents
import {
getDoc,
getDocs,
query,
where,
orderBy,
limit
} from 'firebase/firestore';
// Obtenir un seul document
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('Utilisateur non trouvé');
}
}
// Requête avec filtres
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;
}
// Utilisation
const adminUsers = await getUsersByRole('admin');
console.log('Utilisateurs administrateurs :', adminUsers);
Mettre à jour des documents
import {
updateDoc,
increment,
arrayUnion,
arrayRemove
} from 'firebase/firestore';
async function updateUser(userId, updates) {
const userRef = doc(db, 'users', userId);
await updateDoc(userRef, updates);
}
// Opérations atomiques
await updateUser('userId123', {
loginCount: increment(1),
tags: arrayUnion('premium', 'beta-tester'),
lastLogin: new Date()
});
// Supprimer d'un tableau
await updateUser('userId123', {
tags: arrayRemove('beta-tester')
});
Supprimer des documents
import { deleteDoc } from 'firebase/firestore';
async function deleteUser(userId) {
await deleteDoc(doc(db, 'users', userId));
console.log('Utilisateur supprimé');
}
Écouteurs en temps réel
import { onSnapshot } from 'firebase/firestore';
// Écouter un seul document
const unsubscribe = onSnapshot(
doc(db, 'users', userId),
(doc) => {
console.log('Utilisateur mis à jour :', doc.data());
},
(error) => {
console.error('Erreur d\'écoute :', error);
}
);
// Écouter les résultats d'une requête
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('Publications publiées :', posts);
});
// Arrêter d'écouter
unsubscribe();
unsubscribeQuery();
Règles de sécurité Firestore
Sans règles appropriées, n'importe qui peut lire vos données. Définissez les règles dans la console Firebase > Firestore > Règles :
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Fonction d'aide
function isAuthenticated() {
return request.auth != null;
}
function isOwner(userId) {
return request.auth.uid == userId;
}
// Collection des utilisateurs
match /users/{userId} {
allow read: if isAuthenticated();
allow create: if isAuthenticated() && isOwner(userId);
allow update, delete: if isOwner(userId);
}
// Collection des publications
match /posts/{postId} {
allow read: if true; // Lecture publique
allow create: if isAuthenticated();
allow update, delete: if resource.data.authorId == request.auth.uid;
}
// Sous-collection privée
match /users/{userId}/private/{document} {
allow read, write: if isOwner(userId);
}
}
}
Limitations des requêtes
Firestore a des contraintes :
-
Pas de requêtes OU (utilisez
inavec un tableau ou plusieurs requêtes) - Pas de recherches par caractères génériques (utilisez Algolia ou Meilisearch pour le texte intégral)
- Les requêtes composées nécessitent des index (Firestore crée automatiquement un index sur un seul champ)
-
Limite de 30 disjonctions dans les requêtes
in
Solution de contournement pour les requêtes OU :
// Au lieu de : where('status', '==', 'active') OU 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)
]);
// Fusionner les résultats côté client
Cloud Functions : Logique backend sans serveur
Les fonctions Cloud exécutent du code backend sans gérer de serveurs. Elles se déclenchent lors de modifications de base de données, de requêtes HTTP ou d'événements planifiés.
Configuration
# Installer Firebase CLI
npm install -g firebase-tools
# Connexion
firebase login
# Initialiser les fonctions dans votre projet
firebase init functions
# Sélectionner : JavaScript, ESLint oui, Express.js non
Fonctions HTTP (points d'accès API)
// functions/index.js
const { onRequest } = require('firebase-functions/v2/https');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
// Point d'accès public
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 });
}
});
// Point d'accès protégé (vérifier le jeton d'authentification)
exports.getUserProfile = onRequest(async (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
// Obtenir le jeton de l'en-tête Authorization
const authHeader = req.headers.authorization || '';
const token = authHeader.split('Bearer ')[1];
if (!token) {
return res.status(401).json({ error: 'Non autorisé' });
}
try {
// Vérifier le jeton
const decodedToken = await admin.auth().verifyIdToken(token);
const userId = decodedToken.uid;
// Obtenir les données de l'utilisateur
const userDoc = await db.collection('users').doc(userId).get();
if (!userDoc.exists) {
return res.status(404).json({ error: 'Utilisateur non trouvé' });
}
res.json({
success: true,
data: { id: userId, ...userDoc.data() }
});
} catch (error) {
res.status(401).json({ error: 'Jeton invalide' });
}
});
Déploiement :
firebase deploy --only functions:getUserProfile
Appel depuis le client :
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;
}
Déclencheurs de base de données
const { onDocumentWritten } = require('firebase-functions/v2/firestore');
// Déclencher lorsque le document utilisateur change
exports.onUserUpdate = onDocumentWritten(
'users/{userId}',
async (event) => {
const userId = event.params.userId;
const before = event.data?.before?.data();
const after = event.data?.after?.data();
// Vérifier si l'e-mail a changé
if (before?.email !== after?.email) {
console.log(`L'e-mail de l'utilisateur ${userId} a changé : ${before?.email} → ${after?.email}`);
// Envoyer un e-mail de notification
await admin.auth().getUser(userId);
// Ajouter votre logique d'e-mail ici
}
}
);
// Déclencher lors de la création d'une nouvelle publication
exports.onNewPost = onDocumentWritten(
'posts/{postId}',
async (event) => {
const post = event.data?.after?.data();
if (!post) return; // Document supprimé
// Vérifier s'il s'agit d'un nouveau document
if (!event.data?.before?.exists) {
console.log('Nouvelle publication créée :', post.title);
// Notifier les abonnés
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();
}
}
);
Fonctions planifiées (tâches Cron)
const { onSchedule } = require('firebase-functions/v2/scheduler');
// Exécuter tous les jours à minuit UTC
exports.dailyCleanup = onSchedule('toutes les 24 heures', async (event) => {
console.log('Exécution du nettoyage quotidien');
// Supprimer les anciennes notifications (plus de 30 jours)
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(`Supprimé ${oldNotifs.size} anciennes notifications`);
});
Configuration de l'environnement
# Définir les variables d'environnement
firebase functions:config:set \
stripe.secret="sk_test_xxx" \
email.api_key="key_xxx"
# Accéder aux fonctions
const config = require('firebase-functions/config');
const stripe = require('stripe')(config.stripe.secret);
Cloud Storage : Téléchargement et gestion de fichiers
Stockez les téléchargements d'utilisateurs, les images et les fichiers avec une distribution CDN automatique.
Configuration des règles de stockage
// Console Firebase > Stockage > Règles
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// Dossier des téléchargements d'utilisateurs
match /users/{userId}/{allPaths=**} {
allow read: if true; // Lecture publique
allow write: if request.auth.uid == userId;
allow delete: if request.auth.uid == userId;
}
// Actifs publics
match /public/{allPaths=**} {
allow read: if true;
allow write: if false; // Administrateur uniquement via la console Firebase
}
}
}
Télécharger des fichiers (Client)
import {
getStorage,
ref,
uploadBytesResumable,
getDownloadURL
} from 'firebase/storage';
const storage = getStorage(app);
async function uploadProfileImage(userId, file) {
// Créer une référence de stockage
const storageRef = ref(storage, `users/${userId}/profile/${file.name}`);
// Télécharger le fichier
const uploadTask = uploadBytesResumable(storageRef, file);
return new Promise((resolve, reject) => {
uploadTask.on(
'state_changed',
(snapshot) => {
// Suivre la progression
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(`Téléchargement : ${progress.toFixed(0)}%`);
},
(error) => {
// Gérer les erreurs
switch (error.code) {
case 'storage/unauthorized':
reject(new Error('Vous n\'avez pas la permission'));
break;
case 'storage/canceled':
reject(new Error('Téléchargement annulé'));
break;
default:
reject(new Error('Le téléchargement a échoué'));
}
},
async () => {
// Téléchargement terminé
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
console.log('Fichier disponible à :', downloadURL);
resolve(downloadURL);
}
);
});
}
// Utilisation
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];
if (file) {
const imageUrl = await uploadProfileImage(auth.currentUser.uid, file);
// Enregistrer l'URL dans Firestore
await updateDoc(doc(db, 'users', auth.currentUser.uid), {
profileImage: imageUrl
});
}
Télécharger des fichiers
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; // Pas d'image de profil
}
throw error;
}
}
Supprimer des fichiers
import { deleteObject } from 'firebase/storage';
async function deleteProfileImage(userId) {
const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);
await deleteObject(imageRef);
console.log('Image de profil supprimée');
}
Tester les API Firebase avec Apidog
Firebase fournit des API REST pour tous les services. Les tester directement aide à déboguer les problèmes et à comprendre les requêtes sous-jacentes.
Importer l'API REST Firebase
- Ouvrez Apidog
- Créez un nouveau projet : "Firebase API"
- Importez la spécification OpenAPI de la documentation Firebase
- Ou ajoutez manuellement des points d'accès :
Point d'accès REST 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 }
}
}
Point d'accès d'authentification :
POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={api_key}
Content-Type: application/json
{
"email": "user@example.com",
"password": "secret123",
"returnSecureToken": true
}
Tester le flux d'authentification
- Créer une requête : "Connexion"
- Définir la méthode : POST
- Ajouter l'e-mail/mot de passe dans le corps
- Enregistrer le jeton de réponse comme variable d'environnement
- Utiliser
{{token}}dans les requêtes ultérieures
Déboguer les règles de sécurité
Utilisez la suite d'émulateurs Firebase pour les tests locaux :
# Démarrer l'émulateur
firebase emulators:start
# Tester contre Firestore local
# http://localhost:8080
Bonnes pratiques de production
1. Implémenter une gestion d'erreurs appropriée
// Logique de réessai pour les échecs transitoires
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; // Recul exponentiel
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}
2. Optimiser les performances des requêtes
Ajoutez des index composites pour les requêtes multi-champs :
// Cette requête nécessite un index composite
const q = query(
collection(db, 'posts'),
where('category', '==', 'tech'),
where('views', '>', 1000),
orderBy('views', 'desc')
);
Firestore vous invite à créer l'index avec un lien direct lorsque vous exécutez cette requête.
3. Opérations par lots
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(`Mis à jour ${userIds.length} utilisateurs`);
}
// Maximum 500 opérations par lot
4. Surveiller les coûts
Tarification Firebase :
| Service | Tier gratuit | Payant |
|---|---|---|
| Firestore | 50K lectures/jour | 0,036 $/100K lectures |
| Stockage | 5 Go | 0,023 $/Go |
| Fonctions | 2M invocations | 0,40 $/1M |
| Authentification | 10K/mois | 0,0055 $/100K |
Définissez des alertes budgétaires dans la console Google Cloud.
5. Sécuriser les comptes de service
// FAUX : Ne jamais faire cela dans le code client
admin.initializeApp({
credential: admin.credential.cert(require('./serviceAccountKey.json'))
});
// CORRECT : Utiliser uniquement dans un environnement serveur
const serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
6. Gérer les scénarios hors ligne
// Activer la persistance hors ligne (web)
import { enableMultiTabIndexedDbPersistence } from 'firebase/firestore';
enableMultiTabIndexedDbPersistence(db)
.catch((err) => {
if (err.code === 'failed-precondition') {
// Plusieurs onglets ouverts
} else if (err.code === 'unimplemented') {
// Le navigateur ne prend pas en charge
}
});
// Écouter la connectivité
import { onSnapshot } from 'firebase/firestore';
onSnapshot(doc(db, 'status', 'online'), (doc) => {
if (!doc.exists()) {
console.log('Vous êtes hors ligne');
// Afficher l'interface utilisateur hors ligne
}
});
Problèmes et solutions courants de l'API Firebase
Problème 1 : Erreurs d'autorisation refusée
Symptôme : Erreur : 7 PERMISSION_DENIED
Cause : Les règles de sécurité bloquent l'opération
Correction :
- Vérifiez les règles dans la console Firebase
- Vérifiez que
request.auth.uidcorrespond à l'utilisateur attendu - Testez les règles avec le Playground de règles
Problème 2 : Expiration du jeton
Symptôme : Erreur : Jeton d'ID expiré
Correction :
// Forcer le rafraîchissement du jeton
const user = auth.currentUser;
if (user) {
await user.getIdToken(true); // Forcer le rafraîchissement
}
Problème 3 : Latence de démarrage à froid
Symptôme : Les fonctions Cloud prennent 2 à 5 secondes lors du premier appel
Correction :
// Garder les fonctions "chaudes" avec des pings planifiés
exports.keepWarm = onSchedule('toutes les 60 secondes', async () => {
await fetch('https://votre-fonction.cloudfunctions.net/health');
});
Problème 4 : La requête renvoie des résultats vides
Symptôme : La requête devrait renvoyer des données mais renvoie un tableau vide
Cause : Index manquant ou ordre des champs incorrect
Correction : Vérifiez la console Firestore > Index pour les index composites requis.
Cas d'utilisation réels
Application Fintech : Mises à jour de transactions en temps réel
Une startup de paiement a utilisé Firebase Firestore pour créer des notifications de transactions en temps réel. Lorsqu'un paiement est traité, les fonctions Cloud déclenchent des mises à jour sur tous les tableaux de bord d'administration connectés en moins de 200 ms. Résultat : une réduction de 40 % des tickets de support concernant les transactions "en attente".
E-commerce : Synchronisation des stocks
Un détaillant en ligne synchronise son inventaire sur le web, iOS et Android à l'aide des écouteurs Firestore. Lorsque le stock change, tous les clients sont mis à jour automatiquement. La persistance hors ligne garantit que les employés de l'entrepôt peuvent scanner des articles sans connectivité, avec une synchronisation automatique une fois reconnectés.
SaaS : Authentification multi-locataires
Une plateforme B2B utilise Firebase Auth avec des revendications personnalisées pour l'accès basé sur les rôles. Les utilisateurs administrateurs obtiennent des autorisations élevées via des fonctions Cloud qui valident les configurations de locataires Firestore. Une seule base de code sert plus de 500 organisations avec des données isolées.
Conclusion
L'intégration de l'API Firebase implique quatre services principaux :
- Authentification : Connexion par e-mail, Google, Apple avec des jetons JWT
- Firestore : Base de données NoSQL avec des écouteurs en temps réel et des règles de sécurité
- Cloud Functions : Backend sans serveur déclenché par des événements ou HTTP
- Stockage : Téléchargement de fichiers avec distribution CDN
Vous avez appris les flux d'authentification, les opérations de base de données, le déploiement de fonctions et la gestion de fichiers. Vous avez vu des modèles de production : gestion des erreurs, traitement par lots, support hors ligne et sécurité.
FAQ
Firebase est-il gratuit ?
Oui, Firebase propose un niveau gratuit généreux (plan Spark) incluant 5 Go de stockage, 50K lectures Firestore/jour, 2M invocations de fonctions Cloud et 10K utilisateurs Auth/mois. Les plans payants (Blaze) utilisent une tarification à l'usage.
Puis-je utiliser Firebase avec des bases de données existantes ?
Oui. Utilisez les extensions Firebase pour synchroniser avec PostgreSQL, MySQL ou MongoDB. Ou appelez des API externes depuis les fonctions Cloud pour vous intégrer à des systèmes existants.
Comment migrer de Firebase vers une autre plateforme ?
Exportez les données à l'aide des fonctions d'exportation Firestore ou de la CLI Firebase. Pour les grands ensembles de données, utilisez le pipeline d'exportation Dataflow. La complexité de la migration dépend de la structure de vos données.
Firebase prend-il en charge GraphQL ?
Pas nativement. Utilisez des solutions tierces comme firestore-graphql ou construisez une couche GraphQL avec Cloud Functions et Apollo Server.
Puis-je utiliser Firebase sur site ?
Non. Firebase est exclusivement sur Google Cloud. Pour des alternatives auto-hébergées, envisagez Appwrite, Supabase ou Nhost.
Comment gérer les téléchargements de fichiers de plus de 100 Mo ?
Utilisez les téléchargements reprenables avec découpage (chunking). Le SDK Firebase gère cela automatiquement. Pour les fichiers très volumineux, utilisez directement Google Cloud Storage avec des URL signées.
Que se passe-t-il si je dépasse les limites de requêtes Firestore ?
Les requêtes échouent avec l'erreur FAILED_PRECONDITION. Ajoutez les index requis ou restructurez les requêtes. Firestore fournit des liens directs pour créer les index manquants dans le message d'erreur.
Firebase est-il conforme au RGPD ?
Oui, Firebase offre un traitement des données conforme au RGPD. Activez la résidence des données dans des régions spécifiques, implémentez l'exportation/suppression des données utilisateur et signez l'avenant relatif au traitement des données de Google.




Top comments (0)