Avec la digitalisation croissante dans l'industrie de la restauration, la gestion numérique des menus et des informations sur les allergènes est devenue essentielle.
En tant qu'ingénieur full stack spécialisé dans le front-end avec Angular, j'ai entrepris de développer une application web pour gérer et afficher les informations sur les allergènes des plats d'un restaurant. Face aux contraintes d'hébergement, de stockage des données sécurisé, de coûts et de scalabilité, le choix de la solution technique était crucial.
Dans cet article, j'explique pourquoi j'ai choisi Firebase pour déployer en production ma Web App qrplat.com et ceci sans prise de tête et sans gluten sans symptômes digestifs !
Postulat
L'objectif était de trouver une solution technique simple qui puisse répondre aux besoins suivants :
- Hébergement : un service fiable et performant.
- Stockage des données : une base de données sécurisée et facilement accessible.
- Coûts : une solution économique, surtout au démarrage.
- Scalabilité : une capacité à évoluer facilement en cas de succès.
- Simplicité de mise en œuvre : facile à utiliser pour un développeur peu familier avec le cloud et le déploiement.
Pourquoi Firebase ?
Après avoir exploré plusieurs options, j'ai choisi Firebase pour plusieurs raisons :
- Déploiement et hébergement avec Firebase Hosting
Firebase fournit une CLI (interface de ligne de commande) qui permet de déployer une application web en une seule ligne de commande : firebase deploy
. L’application est immédiatement disponible via une URL 😍.
- Stockage des données avec Cloud Firestore
Cloud Firestore est une base de données NoSQL flexible qui permet de stocker et de synchroniser les données en temps réel. Cela s'est avéré parfait pour gérer les informations variées sur les allergènes pour chaque restaurant. Les requêtes sont rapides et puissantes, et les règles de sécurité permettent de protéger les données sensibles.
La data est accessible via une interface (la console Firebase) avec la possibilité d’utiliser des filtres ainsi qu'un générateur de requêtes pour afficher, interroger, ajouter, modifier et supprimer des données.
- Gestion des coûts
Firebase propose un niveau gratuit (Spark Plan) qui inclut un hébergement gratuit pour des sites à faible trafic, ainsi qu'un quota gratuit pour Cloud Firestore et Firebase Storage. Cela m'a permis de démarrer le projet sans coûts initiaux importants. En cas de succès et d'augmentation du trafic, le passage au plan payant (Blaze Plan) est flexible et basé sur l'utilisation réelle.
- Scalabilité
La scalabilité est intégrée avec Firebase. L'infrastructure est conçue pour gérer des millions d'utilisateurs (suite à la publication de cet article 🤩), ce qui garantit une expérience utilisateur fluide même en cas de forte affluence.
- Simplicité de mise en œuvre
Firebase est conçu pour être accessible même aux développeurs qui ne sont pas experts en cloud et en déploiement. Les services sont bien documentés, et l'intégration avec Angular via AngularFire simplifie grandement le développement.
Installation et implémentation avec Angular
En tant que développeur Angular, l'intégration de Firebase est facilitée grâce au CLI et à AngularFire, une bibliothèque officielle qui simplifie l'utilisation de Firebase avec Angular.
L’installation et la configuration se limitent à quelques lignes. La recette se compose de 4 ingrédients principaux :
- un compte Google
- la CLI Firebase
- la librairie AngularFire
- un projet Angular (16 ou 17 pour une version d'AngularFire 7.x.x)
Etape 1 : créer et configurer un projet Firebase
Connectez-vous à Firebase : https://console.firebase.google.com
Ajoutez un nouveau projet, puis ajoutez une application Web Firebase au projet. À la fin du process, copiez collez la configuration générée dans votre projet Angular (environments/environment.ts
).
Depuis la console Web, activez la connexion Google pour l'authentification Firebase et Cloud Firestore pour la base de données.
Etape 2 : se connecter à Firebase depuis notre projet Angular
Installez Firebase CLI à l'aide de cette commande dans un terminal npm install -g firebase-tools
Utilisez votre compte Google pour vous connecter : firebase login
Connectez votre projet Angular à l’application Web Firebase firebase init
N’activez pas l'émulateur dans l’initialisation, cette partie ne sera pas traitée dans cet article.
Etape 3 : configurer le projet Angular
Ajoutez AngularFire avec cette commande : ng add @angular/fire
Configurez les modules Firebase dans app.module.ts
import { initializeApp, provideFirebaseApp } from '@angular/fire/app';
import { environment } from '../../environments/environment';
import { getAuth, provideAuth } from '@angular/fire/auth';
import { getFirestore, provideFirestore } from '@angular/fire/firestore';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
ReactiveFormsModule,
NgbModule,
// Initialisation de Firebase
provideFirebaseApp(() => initializeApp(environment.firebase)),
// Initialisation du module d'authentification
provideAuth(() => getAuth()),
// Initialisation du module firestore
provideFirestore(() => getFirestore()),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
Et voilà tout est prêt ! Voyons maintenant comment appeler firebase depuis la couche service d'Angular.
Un CRUD pour la collection resto
QRPlat va utiliser une collection contenant une liste de restaurant (document).
Voici le modèle côté typescript :
import {Timestamp} from 'firebase/firestore';
export type Resto = {
id?: string; //id généré par firestore lors de l'insertion
reference: string; //ex: 'dessertissime'-> https://qrplat.com/dessertissime
creationDate: Timestamp;
name: string;
email: string;
}
La structure est identique côté Firestore et s'appelle un document.
Et maintenant le service qui appelle concrètement firebase :
import {
addDoc, // pour ajouter un document
collection,
collectionData,
deleteDoc, // pour supprimer un document
doc, // pour attacher un document
docData, // pour lire un document
Firestore,
limit, // pour limiter le nombre de résultat
orderBy, // pour ordonner le résultat
query, // pour créer la requête
updateDoc,
where,
} from '@angular/fire/firestore';
// ...
@Injectable({
providedIn: 'root',
})
export class RestoService {
const FIREBASE_STORE_RESTO = 'resto'; // resto est le nom de la collection
firestore: Firestore = inject(Firestore);
restoRef = collection(this.firestore, this.FIREBASE_STORE_RESTO);
// ...
}
Crud pour créer un document
createResto(resto: Resto) {
return addDoc(this.restoRef, resto);
}
cRud pour lire un ou plusieurs documents
getRestoById(resto: Resto): Observable<Resto> {
const restoDocRef = doc(
this.firestore,
`${this.FIREBASE_STORE_RESTO}/${resto.id}`
);
return docData(restoDocRef, { idField: 'id' }) as Observable<Resto>;
}
loadRestos(): Observable<Array<Resto>> {
const lastRestosQuery = query(
collection(this.firestore, this.FIREBASE_STORE_RESTO),
orderBy('creationDate', 'desc'),
limit(200),
);
return collectionData(lastRestosQuery, {idField: 'id'}) as Observable<
Array<Resto>
>;
}
crUd pour mettre à jour un document
updateResto(resto: Resto) {
const restoDocRef = doc(
this.firestore,
`${this.FIREBASE_STORE_RESTO}/${resto.id}`
);
return updateDoc(restoDocRef, resto);
}
cruD pour supprimer un document
deleteResto(resto: Resto) {
const restoDocRef = doc(
this.firestore,
`${this.FIREBASE_STORE_RESTO}/${resto.id}`
);
return deleteDoc(restoDocRef);
}
Facile n'est ce pas ? En plus la data synchronisée en temps réel 😮
Si dans mon contrôleur un observable écoute la function loadRestos(), il sera notifié dès qu'un nouveau document resto sera inséré.
export class MyComponent implements OnInit {
restoService: RestoService = inject(RestoService);
restos$: Observable<Array<Resto>>; //mis à jour en temps réel
ngOnInit(): void {
this.restos$ = this.restoService.loadRestos();
}
// ...
}
C'est parfait pour modifier un allergène en temps réel en cas de changement de recette ou simplement en cas d'oubli.
Module d'authentification intégré dans Firebase
Firebase propose un module d'authentification intégré qui simplifie la gestion des utilisateurs. Il prend en charge plusieurs méthodes de connexion, y compris par email/mot de passe, les réseaux sociaux (Google, Facebook, Twitter), et même des fournisseurs d'identité tiers comme GitHub. Ce module offre également des fonctionnalités de gestion des utilisateurs, telles que la réinitialisation de mot de passe et la vérification de l'email.
Pour l'utiliser, vous comprenez mieux l'ajout de cette ligne plus haut provideAuth(() => getAuth())
Voyons de plus près l'utilisation de ce module dans un service dédié.
import {
Auth,
createUserWithEmailAndPassword,
GoogleAuthProvider,
signInWithEmailAndPassword,
signInWithPopup,
signOut,
user
} from "@angular/fire/auth";
import {UserCredential} from "@firebase/auth";
// ...
export class AuthenticationService {
private auth: Auth = inject(Auth);
private provider = new GoogleAuthProvider();
user$ = user(this.auth);
async login(): Promise<UserCredential> {
return await signInWithPopup(this.auth, this.provider);
}
async logout(): Promise<void> {
return signOut(this.auth);
}
async signUp(email: string, password: string): Promise<UserCredential> {
return createUserWithEmailAndPassword(this.auth, email, password);
}
async signIn(email: string, password: string): Promise<UserCredential> {
return signInWithEmailAndPassword(this.auth, email, password);
}
getCurrentUser() {
return this.auth.currentUser;
}
isUserSignedIn() {
return !!this.auth.currentUser;
}
}
J'entends d'ici vos "wouaahhh", "incroyable !!!!", mais ce n'est pas fini 😸
Pour QRPlat j'avais besoin de recevoir un mail à chaque fois qu'un nouveau restaurant était créé. Firebase est de type serverless, c'est à dire qu'il n'y a pas de service backend à proprement parler. En revanche, il y a des Cloud Functions ...
Les Cloud Functions
Firebase Functions est un service de cloud computing qui permet d'exécuter du code backend en réponse à des événements déclenchés par Firebase et d'autres services Google Cloud. Voici quelques points clés sur Firebase Functions :
- Fonctions sans serveur : pas besoin de gérer les serveurs, le code s'exécute en réponse à des événements.
- Événements déclencheurs : réagissez à des événements Firebase (authentification, Firestore, etc.), HTTP, et bien plus.
- Scalabilité automatique : les fonctions s'adaptent automatiquement à la charge.
Voici un exemple de fonction Cloud qui se déclenche lorsqu'un resto est inséré dans Firestore :
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.onDocumentCreate = functions.firestore
.document('resto/{docId}')
.onCreate((snap, context) => {
const newValue = snap.data();
console.log('Document créé avec les données:', newValue);
// Envoi de mail via une API
// ...
});
Règles de sécurité pour Firestore
Voici un dernier point important sur la gestion de l'accès aux données de Firestore avec le code suivant:
service cloud.firestore {
match /databases/{database}/documents {
match /resto/{docId} {
allow read, write: if request.auth != null;
}
}
}
Nous lisons ici que la collection resto est accessible par tout le monde en lecture (via AngularFire) mais que l'écriture est limitée aux utilisateurs connectés uniquement. Nous n'approfondirons pas cette partie, car cela nécessiterait un article dédié.
Conclusion
Le contrat est rempli avec Firebase 🥳 ! J'ai pu développer ma Web App en quelques jours seulement sans me soucier des problématiques de déploiement, de sécurité et tout cela gratuitement. En plus, c'était aussi simple que de suivre une recette sans gluten!
J'ai souhaité écrire cet article en vous présentant les fonctionnalités essentielles de Firebase, mais beaucoup d'autres modules sont disponibles. Par exemple, vous pouvez connecter votre projet à Google Analytics, gérer les paiements en ligne avec Stripe, utiliser le stockage pour héberger des images, consulter les logs, et bien plus encore.
Si vous cherchez une solution efficace et facile pour votre projet, Firebase est votre meilleur allié. Pour plus de détails ou si vous envisagez de l'utiliser, n'hésitez pas à me contacter !