Aller au contenu

Firebase et Astro

Firebase est une plate-forme de développement d’applications qui fournit une base de données NoSQL, une authentification, des souscriptions en temps réel, des fonctions et un stockage.

Consultez notre guide dédié au déploiement sur Firebase hosting.

  • Un projet Firebase avec une application Web configurée.
  • Un projet astro avec server-side rendering (SSR) activé.
  • Des identifiants Firebase : vous aurez besoin de deux ensembles d’identifiants pour connecter Astro à Firebase :
    • Les identifiants de l’application Web : ces informations d’identification seront utilisées par le côté client de votre application. Vous pouvez les trouver dans la console Firebase sous Paramètres du projet > Général. Faites défiler jusqu’à la section Vos applications et cliquez sur l’icône Application Web.
    • Les informations d’identification du projet : ces informations d’identification seront utilisées par le côté serveur de votre application. Vous pouvez les générer dans la console Firebase sous Paramètres du projet > Comptes de service > Firebase Admin SDK > Générer une nouvelle clé privée.

Ajouter les informations d’identification Firebase

Titre de la section Ajouter les informations d’identification Firebase

Pour ajouter vos informations d’identification Firebase à Astro, créez un fichier « .env » à la racine de votre projet avec les variables suivantes :

.env
FIREBASE_PRIVATE_KEY_ID=YOUR_PRIVATE_KEY_ID
FIREBASE_PRIVATE_KEY=YOUR_PRIVATE_KEY
FIREBASE_PROJECT_ID=YOUR_PROJECT_ID
FIREBASE_CLIENT_EMAIL=YOUR_CLIENT_EMAIL
FIREBASE_CLIENT_ID=YOUR_CLIENT_ID
FIREBASE_AUTH_URI=YOUR_AUTH_URI
FIREBASE_TOKEN_URI=YOUR_TOKEN_URI
FIREBASE_AUTH_CERT_URL=YOUR_AUTH_CERT_URL
FIREBASE_CLIENT_CERT_URL=YOUR_CLIENT_CERT_URL

Désormais, ces variables d’environnement sont disponibles pour être utilisées dans votre projet.

Si vous souhaitez disposer d’IntelliSense pour vos variables d’environnement Firebase, modifiez ou créez le fichier « env.d.ts » dans votre répertoire « src/ » et configurez vos types :

src/env.d.ts
interface ImportMetaEnv {
readonly FIREBASE_PRIVATE_KEY_ID: string;
readonly FIREBASE_PRIVATE_KEY: string;
readonly FIREBASE_PROJECT_ID: string;
readonly FIREBASE_CLIENT_EMAIL: string;
readonly FIREBASE_CLIENT_ID: string;
readonly FIREBASE_AUTH_URI: string;
readonly FIREBASE_TOKEN_URI: string;
readonly FIREBASE_AUTH_CERT_URL: string
readonly FIREBASE_CLIENT_CERT_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

Votre projet devrait à présent inclure les fichiers suivants :

  • Répertoiresrc/
    • env.d.ts
  • .env
  • astro.config.mjs
  • package.json

Pour connecter Astro à Firebase, installez les paquets suivants à l’aide de la commande ci-dessous dans votre gestionnaire de paquets préféré :

  • firebase - le SDK Firebase pour le côté client
  • firebase-admin - le SDK Firebase Admin pour le côté serveur
Terminal window
npm install firebase firebase-admin

Ensuite, créez un dossier nommé firebase dans le répertoire src/ et ajoutez deux nouveaux fichiers à ce dossier : client.ts et server.ts.

Dans client.ts, ajoutez le code suivant pour initialiser Firebase côté client à l’aide des informations d’identification de votre application Web et du paquet « firebase » :

src/firebase/client.ts
import { initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: "my-public-api-key",
authDomain: "my-auth-domain",
projectId: "my-project-id",
storageBucket: "my-storage-bucket",
messagingSenderId: "my-sender-id",
appId: "my-app-id",
};
export const app = initializeApp(firebaseConfig);

Dans server.ts, ajoutez le code suivant pour initialiser Firebase côté serveur à l’aide des informations d’identification de votre projet et du package firebase-admin :

src/firebase/server.ts
import type { ServiceAccount } from "firebase-admin";
import { initializeApp, cert, getApps } from "firebase-admin/app";
const activeApps = getApps();
const serviceAccount = {
type: "service_account",
project_id: import.meta.env.FIREBASE_PROJECT_ID,
private_key_id: import.meta.env.FIREBASE_PRIVATE_KEY_ID,
private_key: import.meta.env.FIREBASE_PRIVATE_KEY,
client_email: import.meta.env.FIREBASE_CLIENT_EMAIL,
client_id: import.meta.env.FIREBASE_CLIENT_ID,
auth_uri: import.meta.env.FIREBASE_AUTH_URI,
token_uri: import.meta.env.FIREBASE_TOKEN_URI,
auth_provider_x509_cert_url: import.meta.env.FIREBASE_AUTH_CERT_URL,
client_x509_cert_url: import.meta.env.FIREBASE_CLIENT_CERT_URL,
};
export const app = activeApps.length === 0 ? initializeApp({
credential: cert(serviceAccount as ServiceAccount),
}) : activeApps[0];

À présent, votre projet devrait inclure les fichiers suivants :

  • Répertoiresrc
    • env.d.ts
    • Répertoirefirebase
      • client.ts
      • server.ts
  • .env
  • astro.config.mjs
  • package.json

Ajouter l’authentification avec Firebase

Titre de la section Ajouter l’authentification avec Firebase
  • Un projet Astro initialisé avec Firebase.
  • Un projet Firebase avec l’authentification par e-mail/mot de passe activée dans la console Firebase sous la méthode Authentification > Connexion.

Créer les points de terminaison du serveur d’authentification

Titre de la section Créer les points de terminaison du serveur d’authentification

L’authentification Firebase dans Astro nécessite les trois points de terminaison du serveur Astro suivants :

  • GET /api/auth/signin - pour connecter un utilisateur
  • GET /api/auth/signout - pour déconnecter un utilisateur
  • POST /api/auth/register - pour enregistrer un utilisateur

Créez trois points de terminaison liés à l’authentification dans un nouveau répertoire src/pages/api/auth/ : signin.ts, signout.ts et register.ts.

signin.ts contient le code nécessaire pour connecter un utilisateur via Firebase :

src/pages/api/auth/signin.ts
import type { APIRoute } from "astro";
import { app } from "../../../firebase/server";
import { getAuth } from "firebase-admin/auth";
export const GET: APIRoute = async ({ request, cookies, redirect }) => {
const auth = getAuth(app);
/* Récupération du token depuis les headers de la requête */
const idToken = request.headers.get("Authorization")?.split("Bearer ")[1];
if (!idToken) {
return new Response(
"No token found",
{ status: 401 }
);
}
/* Vérification du token */
try {
await auth.verifyIdToken(idToken);
} catch (error) {
return new Response(
"Invalid token",
{ status: 401 }
);
}
/* Création et configuration du cookie de la session */
const fiveDays = 60 * 60 * 24 * 5 * 1000;
const sessionCookie = await auth.createSessionCookie(idToken, {
expiresIn: fiveDays,
});
cookies.set("session", sessionCookie, {
path: "/",
});
return redirect("/dashboard");
};

signout.ts contient le code nécessaire pour déconnecter un utilisateur en supprimant le cookie de session :

src/pages/api/auth/signout.ts
import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ redirect, cookies }) => {
cookies.delete("session", {
path: "/",
});
return redirect("/signin");
};

register.ts contient le code nécessaire pour enregistrer un utilisateur via Firebase :

src/pages/api/auth/register.ts
import type { APIRoute } from "astro";
import { getAuth } from "firebase-admin/auth";
import { app } from "../../../firebase/server";
export const POST: APIRoute = async ({ request, redirect }) => {
const auth = getAuth(app);
/* Récupération des données du formulaire */
const formData = await request.formData();
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
const name = formData.get("name")?.toString();
if (!email || !password || !name) {
return new Response(
"Missing form data",
{ status: 400 }
);
}
/* Création de l'utilisateur */
try {
await auth.createUser({
email,
password,
displayName: name,
});
} catch (error: any) {
return new Response(
"Something went wrong",
{ status: 400 }
);
}
return redirect("/signin");
};

Après avoir créé les points de terminaison serveur concernant l’authentification, votre projet devrait inclure les fichiers suivants :

  • Répertoiresrc
    • env.d.ts
    • Répertoirefirebase
      • client.ts
      • server.ts
    • Répertoirepages
      • Répertoireapi
        • Répertoireauth
          • signin.ts
          • signout.ts
          • register.ts
  • .env
  • astro.config.mjs
  • package.json

Création des pages qui utiliseront les points de terminaison Firebase :

  • src/pages/register - contiendra le formulaire d’enregistrement utilisateur
  • src/pages/signin - contiendra le formulaire de connexion utilisateur
  • src/pages/dashboard - contiendra un tableau de bord uniquement accessible à un utilisateur authentifié

L’exemple src/pages/register.astro ci-dessous inclut un formulaire qui enverra une requête POST au point de terminaison /api/auth/register. Ce point de terminaison créera un nouvel utilisateur en utilisant les données du formulaire, puis redirigera l’utilisateur vers la page /signin.

src/pages/register.astro
---
import Layout from "../layouts/Layout.astro";
---
<Layout title="Register">
<h1>S'enregistrer</h1>
<p>Avez-vous déjà un compte? <a href="/signin">Sign in</a></p>
<form action="/api/auth/register" method="post">
<label for="name">Nom</label>
<input type="text" name="name" id="name" />
<label for="email" for="email">Email</label>
<input type="email" name="email" id="email" />
<label for="password">Mot de passe</label>
<input type="password" name="password" id="password" />
<button type="submit">Se Connecter</button>
</form>
</Layout>

src/pages/signin.astro utilise l’application serveur Firebase pour vérifier le cookie de session de l’utilisateur. Si l’utilisateur est authentifié, la page redirigera l’utilisateur vers la page /dashboard.

La page d’exemple ci-dessous contient un formulaire qui enverra une requête « POST » au point de terminaison « /api/auth/signin » avec le token d’identification généré par l’application client Firebase.

Le point de terminaison vérifiera le token d’identification et créera un nouveau cookie de session pour l’utilisateur. Ensuite, le point de terminaison redirigera l’utilisateur vers la page « /dashboard ».

src/pages/signin.astro
---
import { app } from "../firebase/server";
import { getAuth } from "firebase-admin/auth";
import Layout from "../layouts/Layout.astro";
/* On vérifie si l'utilisateur est authentifié */
const auth = getAuth(app);
if (Astro.cookies.has("session")) {
const sessionCookie = Astro.cookies.get("session").value;
const decodedCookie = await auth.verifySessionCookie(sessionCookie);
if (decodedCookie) {
return Astro.redirect("/dashboard");
}
}
---
<Layout title="S'enregistrer">
<h1>S'enregistrer</h1>
<p>Nouveau ici ? <a href="/register">Créer un compte</a></p>
<form action="/api/auth/signin" method="post">
<label for="email" for="email">Email</label>
<input type="email" name="email" id="email" />
<label for="password">Mot de passe</label>
<input type="password" name="password" id="password" />
<button type="submit">Se connecter</button>
</form>
</Layout>
<script>
import {
getAuth,
inMemoryPersistence,
signInWithEmailAndPassword,
} from "firebase/auth";
import { app } from "../firebase/client";
const auth = getAuth(app);
// Ceci empêchera le navigateur de stocker les données de session
auth.setPersistence(inMemoryPersistence);
const form = document.querySelector("form") as HTMLFormElement;
form.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(form);
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
if (!email || !password) {
return;
}
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
const idToken = await userCredential.user.getIdToken();
const response = await fetch("/api/auth/signin", {
method: "GET",
headers: {
Authorization: `Bearer ${idToken}`,
},
});
if (response.redirected) {
window.location.assign(response.url);
}
});
</script>

src/pages/dashboard.astro vérifiera le cookie de session de l’utilisateur à l’aide de l’application serveur Firebase. Si l’utilisateur n’est pas authentifié, la page redirigera l’utilisateur vers la page /signin.

La page d’exemple ci-dessous affiche le nom de l’utilisateur et un bouton pour se déconnecter. Cliquer sur le bouton enverra une requête GET au point de terminaison /api/auth/signout.

Le point de terminaison supprimera le cookie de session de l’utilisateur et redirigera l’utilisateur vers la page « /signin ».

src/pages/dashboard.astro
---
import { app } from "../firebase/server";
import { getAuth } from "firebase-admin/auth";
import Layout from "../layouts/Layout.astro";
const auth = getAuth(app);
/* Vérification de la session */
if (!Astro.cookies.has("session")) {
return Astro.redirect("/signin");
}
const sessionCookie = Astro.cookies.get("session").value;
const decodedCookie = await auth.verifySessionCookie(sessionCookie);
const user = await auth.getUser(decodedCookie.uid);
if (!user) {
return Astro.redirect("/signin");
}
---
<Layout title="dashboard">
<h1>Bienvenue {user.displayName}</h1>
<p>Nous sommes heureux de te voir ici</p>
<form action="/api/auth/signout">
<button type="submit">S'inscrire</button>
</form>
</Layout>

Pour ajouter des fournisseurs OAuth à votre application, vous devez les activer dans la console Firebase.

Dans la console Firebase, accédez à la section Authentification et cliquez sur l’onglet Méthode de connexion. Ensuite, cliquez sur le bouton Ajouter un nouveau fournisseur et activez les fournisseurs que vous souhaitez utiliser.

L’exemple ci-dessous utilise le fournisseur Google.

Modifiez la page signin.astro pour ajouter :

  • un bouton pour se connecter avec Google sous le formulaire existant
  • un écouteur d’événement sur le bouton pour gérer le processus de connexion dans le <script> existant.
src/pages/signin.astro
---
import { app } from "../firebase/server";
import { getAuth } from "firebase-admin/auth";
import Layout from "../layouts/Layout.astro";
/* Vérification de l'authentification de l'utilisateur */
const auth = getAuth(app);
if (Astro.cookies.has("session")) {
const sessionCookie = Astro.cookies.get("session").value;
const decodedCookie = await auth.verifySessionCookie(sessionCookie);
if (decodedCookie) {
return Astro.redirect("/dashboard");
}
}
---
<Layout title="Sign in">
<h1>Sign in</h1>
<p>New here? <a href="/register">Create an account</a></p>
<form action="/api/auth/signin" method="post">
<label for="email" for="email">Email</label>
<input type="email" name="email" id="email" />
<label for="password">Password</label>
<input type="password" name="password" id="password" />
<button type="submit">Login</button>
</form>
<button id="google">Sign in with Google</button>
</Layout>
<script>
import {
getAuth,
inMemoryPersistence,
signInWithEmailAndPassword,
GoogleAuthProvider,
signInWithPopup,
} from "firebase/auth";
import { app } from "../firebase/client";
const auth = getAuth(app);
auth.setPersistence(inMemoryPersistence);
const form = document.querySelector("form") as HTMLFormElement;
form.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(form);
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
if (!email || !password) {
return;
}
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
const idToken = await userCredential.user.getIdToken();
const response = await fetch("/api/auth/signin", {
headers: {
Authorization: `Bearer ${idToken}`,
},
});
if (response.redirected) {
window.location.assign(response.url);
}
});
const googleSignin = document.querySelector("#google") as HTMLButtonElement;
googleSignin.addEventListener("click", async () => {
const provider = new GoogleAuthProvider();
const userCredential = await signInWithPopup(auth, provider);
const idToken = await userCredential.user.getIdToken();
const res = await fetch("/api/auth/signin", {
headers: {
Authorization: `Bearer ${idToken}`,
},
});
if (res.redirected) {
window.location.assign(res.url);
}
});
</script>

Lorsque vous cliquez dessus, le bouton de connexion Google ouvrira une fenêtre contextuelle (popup) pour vous connecter avec Google. Une fois que l’utilisateur s’est connecté, il enverra une requête POST au endpoint /api/auth/signin avec le token d’identification généré par le fournisseur OAuth.

Le endpoint vérifiera le token d’identification et créera un nouveau cookie de session pour l’utilisateur. Ensuite, le endpoint redirigera l’utilisateur vers la page /dashboard.

Dans cette recette, la collection Firestore s’appellera friends et contiendra des documents avec les champs suivants :

  • id : généré automatiquement par Firestore
  • name : un champ de type string
  • age : un champ de type number
  • isBestFriend : un champ de type booléen

Création des points de terminaison serveur

Titre de la section Création des points de terminaison serveur

Créez deux nouveaux fichiers dans un nouveau répertoire src/pages/api/friends/ : index.ts et [id].ts. Ceux-ci créeront deux points de terminaison de serveur pour interagir avec la base de données Firestore des manières suivantes :

  • POST /api/friends : pour créer un nouveau document dans la collection “friends”.
  • POST /api/friends/:id : pour mettre à jour un document dans la collection “friends”.
  • DELETE /api/friends/:id : pour supprimer un document dans la collection “friends”.

index.ts contiendra le code pour créer un nouveau document dans la collection “friends” :

src/pages/api/friends/index.ts
import type { APIRoute } from "astro";
import { app } from "../../../firebase/server";
import { getFirestore } from "firebase-admin/firestore";
export const POST: APIRoute = async ({ request, redirect }) => {
const formData = await request.formData();
const name = formData.get("name")?.toString();
const age = formData.get("age")?.toString();
const isBestFriend = formData.get("isBestFriend") === "on";
if (!name || !age) {
return new Response("Missing required fields", {
status: 400,
});
}
try {
const db = getFirestore(app);
const friendsRef = db.collection("friends");
await friendsRef.add({
name,
age: parseInt(age),
isBestFriend,
});
} catch (error) {
return new Response("Something went wrong", {
status: 500,
});
}
return redirect("/dashboard");
};

[id].ts contiendra le code pour mettre à jour et supprimer un document dans la collection “friends” :

src/pages/api/friends/[id].ts
import type { APIRoute } from "astro";
import { app } from "../../../firebase/server";
import { getFirestore } from "firebase-admin/firestore";
const db = getFirestore(app);
const friendsRef = db.collection("friends");
export const POST: APIRoute = async ({ params, redirect, request }) => {
const formData = await request.formData();
const name = formData.get("name")?.toString();
const age = formData.get("age")?.toString();
const isBestFriend = formData.get("isBestFriend") === "on";
if (!name || !age) {
return new Response("Missing required fields", {
status: 400,
});
}
if (!params.id) {
return new Response("Cannot find friend", {
status: 404,
});
}
try {
await friendsRef.doc(params.id).update({
name,
age: parseInt(age),
isBestFriend,
});
} catch (error) {
return new Response("Something went wrong", {
status: 500,
});
}
return redirect("/dashboard");
};
export const DELETE: APIRoute = async ({ params, redirect }) => {
if (!params.id) {
return new Response("Cannot find friend", {
status: 404,
});
}
try {
await friendsRef.doc(params.id).delete();
} catch (error) {
return new Response("Something went wrong", {
status: 500,
});
}
return redirect("/dashboard");
};

Après avoir créé les points de terminaison du serveur pour Firestore, votre répertoire de projet doit maintenant inclure ces nouveaux fichiers :

  • Répertoiresrc
    • env.d.ts
    • Répertoirefirebase
      • client.ts
      • server.ts
    • Répertoirepages
      • Répertoireapi
        • Répertoirefriends
          • index.ts
          • [id].ts
  • .env
  • astro.config.mjs
  • package.json

Créez les pages qui utiliseront les points de terminaison Firestore:

  • src/pages/add.astro - contiendra un formulaire permettant d’ajouter un nouvel ami (“friend”).
  • src/pages/edit/[id].astro - contiendra un formulaire permettant de modifier un ami et un bouton permettant de supprimer un ami.
  • src/pages/friend/[id].astro - contiendra les informations d’un ami.
  • src/pages/dashboard.astro - affichera une liste d’amis.

L’exemple src/pages/add.astro ci-dessous inclut un formulaire qui enverra une requête POST au point de terminaison /api/friends. Ce point de terminaison créera un nouvel ami en utilisant les données du formulaire, puis redirigera l’utilisateur vers la page /dashboard.

src/pages/add.astro
---
import Layout from "../layouts/Layout.astro";
---
<Layout title="Ajouter un nouvel ami">
<h1>Ajouter un nouvel ami</h1>
<form method="post" action="/api/friends">
<label for="name">Nom</label>
<input type="text" id="name" name="name" />
<label for="age">Age</label>
<input type="number" id="age" name="age" />
<label for="isBestFriend">C'est mon meilleur ami ?</label>
<input type="checkbox" id="isBestFriend" name="isBestFriend" />
<button type="submit">Ajouter</button>
</form>
</Layout>

src/pages/edit/[id].astro contiendra un formulaire pour modifier les données d’un ami et un bouton pour supprimer un ami. Lors de la soumission, cette page enverra une requête POST au point de terminaison /api/friends/:id pour mettre à jour les données d’un ami.

Si l’utilisateur clique sur le bouton Supprimer, cette page enverra une requête DELETE au point de terminaison /api/friends/:id pour supprimer un ami.

src/pages/edit/[id].astro
---
import Layout from "../../layouts/Layout.astro";
import { app } from "../../firebase/server";
import { getFirestore } from "firebase-admin/firestore";
interface Friend {
name: string;
age: number;
isBestFriend: boolean;
}
const { id } = Astro.params;
if (!id) {
return Astro.redirect("/404");
}
const db = getFirestore(app);
const friendsRef = db.collection("friends");
const friendSnapshot = await friendsRef.doc(id).get();
if (!friendSnapshot.exists) {
return Astro.redirect("/404");
}
const friend = friendSnapshot.data() as Friend;
---
<Layout title="Edit {friend.name}">
<h1>Editer {friend.name}</h1>
<p>Ici on peut supprimer ou modifier les données d'un ami.</p>
<form method="post" action={`/api/friends/${id}`}>
<label for="name">Nom</label>
<input type="text" id="name" name="name" value={friend.name} />
<label for="age">Age</label>
<input type="number" id="age" name="age" value={friend.age} />
<label for="isBestFriend">C'est mon meilleur ami ?</label>
<input
type="checkbox"
id="isBestFriend"
name="isBestFriend"
checked={friend.isBestFriend}
/>
<button type="submit">Editer l'ami</button>
</form>
<button type="button" id="delete-document">Supprimer</button>
</Layout>
<script>
const deleteButton = document.getElementById(
"delete-document"
) as HTMLButtonElement;
const url = document.querySelector("form")?.getAttribute("action") as string;
deleteButton.addEventListener("click", async () => {
const response = await fetch(url, {
method: "DELETE",
});
if (response.redirected) {
window.location.assign(response.url);
}
});
</script>

src/pages/friend/[id].astro affichera les détails d’un ami.

src/pages/friend/[id].astro
---
import Layout from "../../layouts/Layout.astro";
import { app } from "../../firebase/server";
import { getFirestore } from "firebase-admin/firestore";
interface Friend {
name: string;
age: number;
isBestFriend: boolean;
}
const { id } = Astro.params;
if (!id) {
return Astro.redirect("/404");
}
const db = getFirestore(app);
const friendsRef = db.collection("friends");
const friendSnapshot = await friendsRef.doc(id).get();
if (!friendSnapshot.exists) {
return Astro.redirect("/404");
}
const friend = friendSnapshot.data() as Friend;
---
<Layout title={friend.name}>
<h1>{friend.name}</h1>
<p>Age: {friend.age}</p>
<p>C'est mon meilleur ami: {friend.isBestFriend ? "Yes" : "No"}</p>
</Layout>

Affiche une liste d’entrées avec un bouton d’édition

Titre de la section Affiche une liste d’entrées avec un bouton d’édition

Pour terminer, src/pages/dashboard.astro affichera une liste d’amis. Chaque ami aura un lien vers sa page de détails et un bouton d’édition qui redirigera l’utilisateur vers la page de modification.

src/pages/dashboard.astro
---
import { app } from "../firebase/server";
import { getFirestore } from "firebase-admin/firestore";
import Layout from "../layouts/Layout.astro";
interface Friend {
id: string;
name: string;
age: number;
isBestFriend: boolean;
}
const db = getFirestore(app);
const friendsRef = db.collection("friends");
const friendsSnapshot = await friendsRef.get();
const friends = friendsSnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
})) as Friend[];
---
<Layout title="My friends">
<h1>Amis</h1>
<ul>
{
friends.map((friend) => (
<li>
<a href={`/friend/${friend.id}`}>{friend.name}</a>
<span>({friend.age})</span>
<strong>{friend.isBestFriend ? "Bestie" : "Friend"}</strong>
<a href={`/edit/${friend.id}`}>Editer</a>
</li>
))
}
</ul>
</Layout>

Après avoir créé toutes les pages, vous devriez avoir la structure de fichiers suivante :

  • Répertoiresrc
    • env.d.ts
    • Répertoirefirebase
      • client.ts
      • server.ts
    • Répertoirepages
      • dashboard.astro
      • add.astro
      • Répertoireedit
        • [id].astro
      • Répertoirefriend
        • [id].astro
      • Répertoireapi
        • Répertoirefriends
          • index.ts
          • [id].ts
  • .env
  • astro.config.mjs
  • package.json

Plus de guides sur les services backend