1. Avant de commencer
Dans cet atelier de programmation, vous allez intégrer Firebase Data Connect à une base de données Cloud SQL pour créer une application Web d'avis sur les films. L'application terminée montre comment Firebase Data Connect simplifie le processus de création d'applications SQL. Il comprend les fonctionnalités suivantes:
- Authentification:implémentez une authentification personnalisée pour les requêtes et les mutations de votre application, afin de vous assurer que seuls les utilisateurs autorisés peuvent interagir avec vos données.
- Schéma GraphQL:créez et gérez vos structures de données à l'aide d'un schéma GraphQL flexible adapté aux besoins d'une application Web d'avis sur les films.
- Requêtes et mutations SQL:récupérez, mettez à jour et gérez les données dans Cloud SQL à l'aide de requêtes et de mutations alimentées par GraphQL.
- Recherche avancée avec correspondance partielle de chaîne:utilisez des filtres et des options de recherche pour trouver des films en fonction de champs tels que le titre, la description ou les tags.
- Facultatif: Intégration de la recherche vectorielle:ajoutez une fonctionnalité de recherche de contenu à l'aide de la recherche vectorielle de Firebase Data Connect pour offrir une expérience utilisateur enrichie en fonction des entrées et des préférences.
Conditions préalables
Vous devez avoir des connaissances de base sur JavaScript.
Au programme
- Configurez Firebase Data Connect avec des émulateurs locaux.
- Concevez un schéma de données à l'aide de Data Connect et de GraphQL.
- Écrire et tester différentes requêtes et mutations pour une application d'avis sur les films
- Découvrez comment Firebase Data Connect génère et utilise le SDK dans l'application.
- Déployez votre schéma et gérez la base de données efficacement.
Ce dont vous avez besoin
- Git
- Visual Studio Code
- Installer Node.js à l'aide de nvm-windows (Windows) ou de nvm (macOS/Linux)
- Si vous ne l'avez pas déjà fait, créez un projet Firebase dans la console Firebase.
- (Facultatif) Pour la recherche vectorielle, passez à la formule Blaze pour votre projet
Configurer votre environnement de développement
Cette section vous explique comment configurer l'environnement pour commencer à créer votre application d'avis sur les films à l'aide de Firebase Data Connect.
Étape 1: Cloner le dépôt du projet
Commencez par cloner le dépôt du projet et installer les dépendances requises:
git clone https://github.com/firebaseextended/codelab-dataconnect-web cd codelab-dataconnect-web cd ./app && npm i npm run dev
- Après avoir exécuté ces commandes, ouvrez http://localhost:5173 dans votre navigateur pour voir l'application Web s'exécuter en local. Il s'agit de l'interface utilisateur qui vous permet de créer l'application de critiques de films et d'interagir avec ses fonctionnalités.
Étape 2: Ouvrir le projet dans Visual Studio Code
Ouvrez le dossier codelab-dataconnect-web
cloné à l'aide de Visual Studio Code. C'est là que vous définirez votre schéma, écrirez des requêtes et testerez le fonctionnement de l'application.
Étape 3: Installer l'extension Visual Studio pour Firebase Data Connect
Pour utiliser les fonctionnalités Data Connect, installez l'extension Visual Studio Firebase Data Connect.Vous pouvez également l'installer à partir de Visual Studio Code Marketplace ou la rechercher dans VS Code.
- Vous pouvez également l'installer à partir de Visual Studio Code Marketplace ou la rechercher dans VS Code.
Étape 4: Créez un projet Firebase
Accédez à la console Firebase pour créer un projet Firebase si vous n'en avez pas déjà un. Ensuite, dans l'extension VSCode Firebase Data Connect:
- Cliquez sur le bouton Se connecter.
- Cliquez sur Connecter un projet Firebase, puis sélectionnez le projet que vous avez créé dans la console Firebase.
Étape 5: Démarrez les émulateurs Firebase
Dans l'extension VSCode Firebase Data Connect, cliquez sur "Start Emulators" (Démarrer les émulateurs) et vérifiez que les émulateurs s'exécutent dans le terminal.
2. Examiner le code de démarrage
Dans cette section, vous allez explorer les principaux aspects du code de démarrage de l'application. Bien que certaines fonctionnalités manquent à l'application, il est utile de comprendre sa structure globale.
Structure des dossiers et des fichiers
Voici un bref aperçu de la structure des dossiers et des fichiers de l'application:
dataconnect/
Contient des configurations Firebase Data Connect, des connecteurs (qui définissent les requêtes et les mutations) et des fichiers de schéma.
schema/schema.gql
: définit le schéma GraphQLconnector/queries.gql
: requêtes requises dans votre application.connector/mutations.gql
: mutations nécessaires dans votre application.connector/connector.yaml:
Fichier de configuration pour la génération du SDK
app/src/
Contient la logique de l'application et l'interaction avec Firebase Data Connect.
firebase.ts
: configuration pour vous connecter à une application Firebase dans la console.lib/dataconnect-sdk/
: ce dossier contient le SDK généré. Vous pouvez modifier l'emplacement de génération du SDK dans le fichier connector/connector.yaml. Les SDK seront alors générés automatiquement chaque fois que vous définirez une requête ou une mutation.
3. Définir un schéma pour les critiques de films
Dans cette section, vous allez définir la structure et les relations entre les principales entités de l'application de films dans un schéma. Les entités telles que Movie
, User
, Actor
et Review
sont mappées sur des tables de base de données, et des relations sont établies à l'aide de directives de schéma Firebase Data Connect et GraphQL. Une fois la recherche vectorielle intégrée, votre application sera prête à gérer tout ce qui est nécessaire : recherche des films les mieux notés et filtrage par genre, possibilité pour les utilisateurs de laisser des avis, de marquer des favoris, d'explorer des films similaires ou de trouver des recommandations de films en fonction de ce qu'ils ont saisi à l'aide de la recherche vectorielle.
Entités et relations principales
Le type Movie
contient des informations clés telles que le titre, le genre et les tags, que l'application utilise pour les recherches et les profils de films. Le type User
permet de suivre les interactions des utilisateurs, comme les avis et les favoris. Reviews
permet aux utilisateurs de se connecter à des films, ce qui permet à l'application d'afficher les notes et les commentaires générés par les utilisateurs.
Les relations entre les films, les acteurs et les utilisateurs rendent l'application plus dynamique. La table de jointure MovieActor
permet d'afficher les détails de la distribution et les filmographies des acteurs. Le type FavoriteMovie
permet aux utilisateurs d'ajouter des films à leurs favoris. L'application peut ainsi afficher une liste personnalisée de favoris et mettre en avant les choix populaires.
Tableau des films
Le type "Movie" définit la structure principale d'une entité de film, y compris des champs tels que "title", "genre", "releaseYear" et "rating".
Copiez et collez l'extrait de code dans votre fichier dataconnect/schema/schema.gql
:
type Movie
@table {
id: UUID! @default(expr: "uuidV4()")
title: String!
imageUrl: String!
releaseYear: Int
genre: String
rating: Float
description: String
tags: [String]
}
Points à retenir :
- id:UUID unique pour chaque film, généré à l'aide de
@default(expr: "uuidV4()")
.
Table MovieMetadata
Le type MovieMetadata établit une relation individuelle avec le type Movie. Elle inclut des données supplémentaires telles que le réalisateur du film.
Copiez et collez l'extrait de code dans votre fichier dataconnect/schema/schema.gql
:
type MovieMetadata
@table {
# @ref creates a field in the current table (MovieMetadata)
# It is a reference that holds the primary key of the referenced type
# In this case, @ref(fields: "movieId", references: "id") is implied
movie: Movie! @ref
# movieId: UUID <- this is created by the above @ref
director: String
}
Points à retenir :
- Film ! @ref: fait référence au type
Movie
, établissant une relation de clé étrangère.
Table des acteurs
Copiez et collez l'extrait de code dans votre fichier dataconnect/schema/schema.gql
:
type Actor @table {
id: UUID!
imageUrl: String!
name: String! @col(name: "name", dataType: "varchar(30)")
}
Le type Actor
représente un acteur dans la base de données de films, où chaque acteur peut faire partie de plusieurs films, formant ainsi une relation de plusieurs à plusieurs.
Tableau "MovieActor"
Copiez et collez l'extrait de code dans votre fichier dataconnect/schema/schema.gql
:
type MovieActor @table(key: ["movie", "actor"]) {
# @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
# In this case, @ref(fields: "id") is implied
movie: Movie!
# movieId: UUID! <- this is created by the implied @ref, see: implicit.gql
actor: Actor!
# actorId: UUID! <- this is created by the implied @ref, see: implicit.gql
role: String! # "main" or "supporting"
}
Points à retenir :
- movie:fait référence au type "Movie", génère implicitement une clé étrangère movieId: UUID!.
- acteur:fait référence au type d'acteur, génère implicitement une clé étrangère actorId: UUID!.
- role:définit le rôle de l'acteur dans le film (par exemple, "principal" ou "secondaire").
Tableau des utilisateurs
Le type User
définit une entité utilisateur qui interagit avec des films en laissant des avis ou en les ajoutant à ses favoris.
Copiez et collez l'extrait de code dans votre fichier dataconnect/schema/schema.gql
:
type User
@table {
id: String! @col(name: "auth_uid")
username: String! @col(dataType: "varchar(50)")
# The following are generated from the @ref in the Review table
# reviews_on_user
# movies_via_Review
}
Tableau "FavoriteMovie"
Le type FavoriteMovie
est une table de jointure qui gère les relations de plusieurs à plusieurs entre les utilisateurs et leurs films ou acteurs préférés. Chaque table lie un User
à un Movie
.
Copiez et collez l'extrait de code dans votre fichier dataconnect/schema/schema.gql
:
type FavoriteMovie
@table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
# @ref is implicit
user: User!
movie: Movie!
}
Points à retenir :
- movie:fait référence au type "Movie", génère implicitement une clé étrangère movieId: UUID!.
- user:fait référence au type d'utilisateur, génère implicitement une clé étrangère userId: UUID!.
Tableau d'avis
Le type d'avis représente l'entité d'avis et lie les types d'utilisateur et de film dans une relation plusieurs à plusieurs (un utilisateur peut laisser plusieurs avis, et chaque film peut en avoir plusieurs).
Copiez et collez l'extrait de code dans votre fichier dataconnect/schema/schema.gql
:
type Review @table(name: "Reviews", key: ["movie", "user"]) {
id: UUID! @default(expr: "uuidV4()")
user: User!
movie: Movie!
rating: Int
reviewText: String
reviewDate: Date! @default(expr: "request.time")
}
Points à retenir :
- user:fait référence à l'utilisateur qui a laissé l'avis.
- movie:fait référence au film en cours d'examen.
- reviewDate:défini automatiquement sur l'heure à laquelle l'avis est créé à l'aide de
@default(expr: "request.time")
.
Champs et valeurs par défaut générés automatiquement
Le schéma utilise des expressions telles que @default(expr: "uuidV4()")
pour générer automatiquement des ID et des codes temporels uniques. Par exemple, le champ d'ID des types "Film" et "Avis" est automatiquement renseigné par un UUID lorsqu'un nouvel enregistrement est créé.
Maintenant que le schéma est défini, votre application de films dispose d'une base solide pour sa structure de données et ses relations.
4. Récupération des meilleurs et derniers films
Dans cette section, vous allez insérer des données fictives sur les films dans les émulateurs locaux, puis implémenter les connecteurs (requêtes) et le code TypeScript pour appeler ces connecteurs dans l'application Web. À la fin, votre application pourra récupérer et afficher de manière dynamique les films les mieux notés et les plus récents directement à partir de la base de données.
Insérer des données fictives sur des films, des acteurs et des critiques
- Dans VS Code, ouvrez
dataconnect/moviedata_insert.gql
. Assurez-vous que les émulateurs de l'extension Firebase Data Connect sont en cours d'exécution. - Un bouton Run (local) (Exécuter (local)) devrait s'afficher en haut du fichier. Cliquez dessus pour insérer les données fictives sur les films dans votre base de données.
- Vérifiez le terminal Data Connect Execution (Exécution de la connexion aux données) pour vous assurer que les données ont bien été ajoutées.
Implémenter le connecteur
- Ouvrez
dataconnect/movie-connector/queries.gql
. Vous trouverez une requêteListMovies
de base dans les commentaires:
query ListMovies @auth(level: PUBLIC) {
movies {
id
title
imageUrl
releaseYear
genre
rating
tags
description
}
}
Cette requête récupère tous les films et leurs informations (par exemple, l'ID, le titre et l'année de sortie). Cependant, il ne trie pas les films.
- Remplacez la requête
ListMovies
par celle ci-dessous pour ajouter des options de tri et de limite:
# List subset of fields for movies
query ListMovies($orderByRating: OrderDirection, $orderByReleaseYear: OrderDirection, $limit: Int) @auth(level: PUBLIC) {
movies(
orderBy: [
{ rating: $orderByRating },
{ releaseYear: $orderByReleaseYear }
]
limit: $limit
) {
id
title
imageUrl
releaseYear
genre
rating
tags
description
}
}
Cliquez sur le bouton Run (local) (Exécuter (local)) pour exécuter la requête sur votre base de données locale. Vous pouvez également saisir les variables de requête dans le volet de configuration avant l'exécution.
Points à retenir :
- movies(): champ de requête GraphQL permettant d'extraire des données de film à partir de la base de données.
- orderByRating:paramètre permettant de trier les films par note (croissant/décroissant).
- orderByReleaseYear:paramètre permettant de trier les films par année de sortie (ascendant/descendant).
- limit:limite le nombre de films renvoyés.
Intégrer des requêtes dans l'application Web
Dans cette partie, vous allez utiliser les requêtes définies dans la section précédente dans votre application Web. Les émulateurs Firebase Data Connect génèrent des SDK en fonction des informations contenues dans les fichiers .gql (schema.gql, queries.gql, mutations.gql) et connector.yaml. Vous pouvez appeler ces SDK directement dans votre application.
- Dans
MovieService
(app/src/lib/MovieService.tsx
), désactivez la balise de commentaire de l'instruction d'importation en haut de la page:
import { listMovies, ListMoviesData, OrderDirection } from "@movie/dataconnect";
La fonction listMovies
, le type de réponse ListMoviesData
et l'énumération OrderDirection
sont tous des SDK générés par les émulateurs Firebase Data Connect en fonction du schéma et des requêtes que vous avez précédemment définis .
- Remplacez les fonctions
handleGetTopMovies
ethandleGetLatestMovies
par le code suivant:
// Fetch top-rated movies
export const handleGetTopMovies = async (
limit: number
): Promise<ListMoviesData["movies"] | null> => {
try {
const response = await listMovies({
orderByRating: OrderDirection.DESC,
limit,
});
return response.data.movies;
} catch (error) {
console.error("Error fetching top movies:", error);
return null;
}
};
// Fetch latest movies
export const handleGetLatestMovies = async (
limit: number
): Promise<ListMoviesData["movies"] | null> => {
try {
const response = await listMovies({
orderByReleaseYear: OrderDirection.DESC,
limit,
});
return response.data.movies;
} catch (error) {
console.error("Error fetching latest movies:", error);
return null;
}
};
Points à retenir :
- listMovies:fonction générée automatiquement qui appelle la requête listMovies pour récupérer une liste de films. Il inclut des options permettant de trier les résultats par note ou par année de sortie, et de limiter leur nombre.
- ListMoviesData:type de résultats utilisé pour afficher le top 10 et les derniers films sur la page d'accueil.
Voir une démo
Actualisez votre application Web pour voir la requête en action. La page d'accueil affiche désormais de manière dynamique la liste des films, en récupérant les données directement à partir de votre base de données locale. Les films les mieux notés et les plus récents s'affichent automatiquement, reflétant les données que vous venez de configurer.
5. Afficher les détails d'un film et d'un acteur
Dans cette section, vous allez implémenter la fonctionnalité permettant de récupérer des informations détaillées sur un film ou un acteur à l'aide de leurs ID uniques. Cela implique non seulement d'extraire les données de leurs tables respectives, mais aussi d'associer des tables associées pour afficher des informations complètes, telles que des critiques de films et des filmographies d'acteurs.
Implémenter des connecteurs
- Ouvrez
dataconnect/movie-connector/queries.gql
dans votre projet. - Ajoutez les requêtes suivantes pour récupérer des informations sur les films et les acteurs:
# Get movie by id
query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
movie(id: $id) {
id
title
imageUrl
releaseYear
genre
rating
description
tags
metadata: movieMetadatas_on_movie {
director
}
mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
id
name
imageUrl
}
supportingActors: actors_via_MovieActor(
where: { role: { eq: "supporting" } }
) {
id
name
imageUrl
}
reviews: reviews_on_movie {
id
reviewText
reviewDate
rating
user {
id
username
}
}
}
}
# Get actor by id
query GetActorById($id: UUID!) @auth(level: PUBLIC) {
actor(id: $id) {
id
name
imageUrl
mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) {
id
title
genre
tags
imageUrl
}
supportingActors: movies_via_MovieActor(
where: { role: { eq: "supporting" } }
) {
id
title
genre
tags
imageUrl
}
}
}
- Enregistrez les modifications et examinez les requêtes.
Points à retenir :
movie()
/actor()
: champs de requête GraphQL permettant d'extraire un seul film ou acteur de la table "Films" ou "Acteurs"._on_
: permet un accès direct aux champs d'un type associé qui présente une relation de clé étrangère. Par exemple,reviews_on_movie
extrait toutes les critiques associées à un film spécifique._via_
: permet de naviguer dans les relations de type "plusieurs à plusieurs" via une table de jointure. Par exemple,actors_via_MovieActor
accède au type d'acteur via la table de jointure MovieActor, et la conditionwhere
filtre les acteurs en fonction de leur rôle (par exemple, "principal" ou "secondaire").
Dans le volet d'exécution de Data Connect, vous pouvez tester la requête en saisissant des ID fictifs, par exemple:
{"id": "550e8400-e29b-41d4-a716-446655440000"}
Cliquez sur Run (local) (Exécuter (local)) pour que GetMovieById
récupère les informations sur "Quantum Paradox" (le faux film auquel l'ID ci-dessus fait référence).
Intégrer des requêtes dans l'application Web
- Dans
MovieService
(app/src/lib/MovieService.tsx
), désactivez la mise en commentaire des importations suivantes:
import { getMovieById, GetMovieByIdData } from "@movie/dataconnect";
import { GetActorByIdData, getActorById } from "@movie/dataconnect";
- Remplacez les fonctions
handleGetMovieById
ethandleGetActorById
par le code suivant:
// Fetch movie details by ID
export const handleGetMovieById = async (
movieId: string
) => {
try {
const response = await getMovieById({ id: movieId });
if (response.data.movie) {
return response.data.movie;
}
return null;
} catch (error) {
console.error("Error fetching movie:", error);
return null;
}
};
// Calling generated SDK for GetActorById
export const handleGetActorById = async (
actorId: string
): Promise<GetActorByIdData["actor"] | null> => {
try {
const response = await getActorById({ id: actorId });
if (response.data.actor) {
return response.data.actor;
}
return null;
} catch (error) {
console.error("Error fetching actor:", error);
return null;
}
};
Points à retenir :
getMovieById
/getActorById
: fonctions générées automatiquement qui appellent les requêtes que vous avez définies et qui récupèrent des informations détaillées sur un film ou un acteur spécifique.GetMovieByIdData
/GetActorByIdData
: types de résultats utilisés pour afficher les détails des films et des acteurs dans l'application.
Voir une démo
Accédez maintenant à la page d'accueil de votre application Web. Cliquez sur un film pour afficher tous ses détails, y compris les acteurs et les avis, qui sont des informations extraites de tables associées. De même, si vous cliquez sur un acteur, les films dans lesquels il a joué s'affichent.
6. Gérer l'authentification des utilisateurs
Dans cette section, vous allez implémenter la fonctionnalité de connexion et de déconnexion des utilisateurs à l'aide de Firebase Authentication. Vous utiliserez également les données Firebase Authentication pour récupérer ou insérer directement des données utilisateur dans Firebase DataConnect, ce qui vous permettra de gérer les utilisateurs de manière sécurisée dans votre application.
Implémenter des connecteurs
- Ouvrez
mutations.gql
dansdataconnect/movie-connector/
. - Ajoutez la mutation suivante pour créer ou mettre à jour l'utilisateur authentifié actuel:
# Create or update the current authenticated user
mutation UpsertUser($username: String!) @auth(level: USER) {
user_upsert(
data: {
id_expr: "auth.uid"
username: $username
}
)
}
Points à retenir :
id_expr: "auth.uid"
: cette méthode utiliseauth.uid
, qui est fourni directement par Firebase Authentication, et non par l'utilisateur ou l'application. Elle ajoute une couche de sécurité supplémentaire en veillant à ce que l'ID utilisateur soit géré de manière sécurisée et automatique.
Ensuite, ouvrez queries.gql
dans dataconnect/movie-connector/
.
Ajoutez la requête suivante pour extraire l'utilisateur actuel:
# Get user by ID
query GetCurrentUser @auth(level: USER) {
user(key: { id_expr: "auth.uid" }) {
id
username
reviews: reviews_on_user {
id
rating
reviewDate
reviewText
movie {
id
title
}
}
favoriteMovies: favorite_movies_on_user {
movie {
id
title
genre
imageUrl
releaseYear
rating
description
tags
metadata: movieMetadatas_on_movie {
director
}
}
}
}
}
Ce qu'il faut retenir :
auth.uid
: cette valeur est récupérée directement à partir de Firebase Authentication, ce qui garantit un accès sécurisé aux données spécifiques à l'utilisateur._on_
Champs: ces champs représentent les tables de jointure:reviews_on_user
: extrait toutes les critiques associées à l'utilisateur, y compris l'ID et le titre du film.favorite_movies_on_user
: récupère tous les films marqués comme favoris par l'utilisateur, y compris des informations détaillées telles que le genre, l'année de sortie, la classification et les métadonnées.
Intégrer des requêtes dans l'application Web
- Dans MovieService (
app/src/lib/MovieService.tsx
), décommentez les importations suivantes:
import { upsertUser } from "@movie/dataconnect";
import { getCurrentUser, GetCurrentUserData } from "@movie/dataconnect";
- Remplacez les fonctions
handleAuthStateChange
ethandleGetCurrentUser
par le code suivant:
// Handle user authentication state changes and upsert user
export const handleAuthStateChange = (
auth: any,
setUser: (user: User | null) => void
) => {
return onAuthStateChanged(auth, async (user) => {
if (user) {
setUser(user);
const username = user.email?.split("@")[0] || "anon";
await upsertUser({ username });
} else {
setUser(null);
}
});
};
// Fetch current user profile
export const handleGetCurrentUser = async (): Promise<
GetCurrentUserData["user"] | null
> => {
try {
const response = await getCurrentUser();
return response.data.user;
} catch (error) {
console.error("Error fetching user profile:", error);
return null;
}
};
Points à retenir :
handleAuthStateChange
: cette fonction écoute les changements d'état de l'authentification. Lorsqu'un utilisateur se connecte, ses données sont définies et la mutationupsertUser
est appelée pour créer ou mettre à jour ses informations dans la base de données.handleGetCurrentUser
: extrait le profil de l'utilisateur actuel à l'aide de la requêtegetCurrentUser
, qui récupère ses avis et ses films préférés.
Voir une démo
Cliquez maintenant sur le bouton "Se connecter avec Google" dans la barre de navigation. Vous pouvez vous connecter à l'aide de l'émulateur Firebase Auth. Après vous être connecté, cliquez sur "Mon profil". Pour le moment, il sera vide, mais vous avez posé les bases de la gestion des données spécifiques à l'utilisateur dans votre application.
7. Implémenter des interactions utilisateur
Dans cette section, vous allez implémenter les interactions utilisateur dans l'application d'avis sur les films, ce qui permettra aux utilisateurs de gérer leurs films préférés et de laisser ou supprimer des avis.
Implémenter des connecteurs
- Ouvrez
mutations.gql
dansdataconnect/movie-connector/
. - Ajoutez les mutations suivantes pour gérer l'ajout de films aux favoris:
# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}
# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}
Points à retenir :
userId_expr: "auth.uid"
: utiliseauth.uid
, qui est fourni directement par Firebase Authentication, ce qui garantit que seules les données de l'utilisateur authentifié sont accessibles ou modifiées.
- Ensuite, ouvrez
queries.gql
dansdataconnect/movie-connector/
. - Ajoutez la requête suivante pour vérifier si un film est ajouté aux favoris:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
movieId
}
}
Points à retenir :
auth.uid
: garantit un accès sécurisé aux données spécifiques à l'utilisateur à l'aide de Firebase Authentication.favorite_movie
: vérifie la table de jointurefavorite_movies
pour voir si un film spécifique est marqué comme favori par l'utilisateur actuel.
Intégrer des requêtes dans l'application Web
- Dans
MovieService
(app/src/lib/MovieService.tsx
), désactivez la mise en commentaire des importations suivantes:
import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from "@movie/dataconnect";
- Remplacez les fonctions
handleAddFavoritedMovie
,handleDeleteFavoritedMovie
ethandleGetIfFavoritedMovie
par le code suivant:
// Add a movie to user's favorites
export const handleAddFavoritedMovie = async (
movieId: string
): Promise<void> => {
try {
await addFavoritedMovie({ movieId });
} catch (error) {
console.error("Error adding movie to favorites:", error);
throw error;
}
};
// Remove a movie from user's favorites
export const handleDeleteFavoritedMovie = async (
movieId: string
): Promise<void> => {
try {
await deleteFavoritedMovie({ movieId });
} catch (error) {
console.error("Error removing movie from favorites:", error);
throw error;
}
};
// Check if the movie is favorited by the user
export const handleGetIfFavoritedMovie = async (
movieId: string
): Promise<boolean> => {
try {
const response = await getIfFavoritedMovie({ movieId });
return !!response.data.favorite_movie;
} catch (error) {
console.error("Error checking if movie is favorited:", error);
return false;
}
};
Points à retenir :
handleAddFavoritedMovie
ethandleDeleteFavoritedMovie
: utilisez les mutations pour ajouter ou supprimer un film des favoris de l'utilisateur de manière sécurisée.handleGetIfFavoritedMovie
: utilise la requêtegetIfFavoritedMovie
pour vérifier si un film est marqué comme favori par l'utilisateur.
Voir une démo
Vous pouvez désormais ajouter ou supprimer des films de vos favoris en cliquant sur l'icône en forme de cœur sur les fiches et la page d'informations des films. Vous pouvez également consulter vos films préférés sur votre page de profil.
Implémenter des avis des utilisateurs
Ensuite, vous allez implémenter la section de gestion des avis des utilisateurs dans l'application.
Implémenter des connecteurs
- Dans
mutations.gql
(dataconnect/movie-connector/mutations.gql
): ajoutez les mutations suivantes:
# Add a review for a movie
mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
@auth(level: USER) {
review_insert(
data: {
userId_expr: "auth.uid"
movieId: $movieId
rating: $rating
reviewText: $reviewText
reviewDate_date: { today: true }
}
)
}
# Delete a user's review for a movie
mutation DeleteReview($movieId: UUID!) @auth(level: USER) {
review_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}
Points à retenir :
userId_expr: "auth.uid"
: garantit que les avis sont associés à l'utilisateur authentifié.reviewDate_date: { today: true }
: génère automatiquement la date actuelle de l'avis à l'aide de DataConnect, ce qui élimine la saisie manuelle.
Intégrer des requêtes dans l'application Web
- Dans
MovieService
(app/src/lib/MovieService.tsx
), désactivez la mise en commentaire des importations suivantes:
import { addReview, deleteReview } from "@movie/dataconnect";
- Remplacez les fonctions
handleAddReview
ethandleDeleteReview
par le code suivant:
// Add a review to a movie
export const handleAddReview = async (
movieId: string,
rating: number,
reviewText: string
): Promise<void> => {
try {
await addReview({ movieId, rating, reviewText });
} catch (error) {
console.error("Error adding review:", error);
throw error;
}
};
// Delete a review from a movie
export const handleDeleteReview = async (movieId: string): Promise<void> => {
try {
await deleteReview({ movieId });
} catch (error) {
console.error("Error deleting review:", error);
throw error;
}
};
Points à retenir :
handleAddReview
: appelle la mutationaddReview
pour ajouter un avis sur le film spécifié, en l'associant de manière sécurisée à l'utilisateur authentifié.handleDeleteReview
: utilise la mutationdeleteReview
pour supprimer un avis sur un film par l'utilisateur authentifié.
Voir une démo
Les utilisateurs peuvent désormais laisser des avis sur les films sur la page d'informations correspondante. Ils peuvent également consulter et supprimer leurs avis sur leur page de profil, ce qui leur permet de contrôler entièrement leurs interactions avec l'application.
8. Filtres avancés et mise en correspondance partielle du texte
Dans cette section, vous allez implémenter des fonctionnalités de recherche avancées qui permettront aux utilisateurs de rechercher des films en fonction d'une plage d'âges et d'années de sortie, de filtrer par genre et par tag, d'effectuer une correspondance partielle de texte dans les titres ou les descriptions, et même de combiner plusieurs filtres pour obtenir des résultats plus précis.
Implémenter des connecteurs
- Ouvrez
queries.gql
dansdataconnect/movie-connector/
. - Ajoutez la requête suivante pour prendre en charge diverses fonctionnalités de recherche:
# Search for movies, actors, and reviews
query SearchAll(
$input: String
$minYear: Int!
$maxYear: Int!
$minRating: Float!
$maxRating: Float!
$genre: String!
) @auth(level: PUBLIC) {
moviesMatchingTitle: movies(
where: {
_and: [
{ releaseYear: { ge: $minYear } }
{ releaseYear: { le: $maxYear } }
{ rating: { ge: $minRating } }
{ rating: { le: $maxRating } }
{ genre: { contains: $genre } }
{ title: { contains: $input } }
]
}
) {
id
title
genre
rating
imageUrl
}
moviesMatchingDescription: movies(
where: {
_and: [
{ releaseYear: { ge: $minYear } }
{ releaseYear: { le: $maxYear } }
{ rating: { ge: $minRating } }
{ rating: { le: $maxRating } }
{ genre: { contains: $genre } }
{ description: { contains: $input } }
]
}
) {
id
title
genre
rating
imageUrl
}
actorsMatchingName: actors(where: { name: { contains: $input } }) {
id
name
imageUrl
}
reviewsMatchingText: reviews(where: { reviewText: { contains: $input } }) {
id
rating
reviewText
reviewDate
movie {
id
title
}
user {
id
username
}
}
}
Points à retenir :
- Opérateur
_and
: combine plusieurs conditions dans une seule requête, ce qui permet de filtrer la recherche par plusieurs champs, commereleaseYear
,rating
etgenre
. - Opérateur
contains
: recherche des correspondances textuelles partielles dans les champs. Dans cette requête, il recherche des correspondances danstitle
,description
,name
oureviewText
. - Clause
where
: spécifie les conditions de filtrage des données. Chaque section (films, acteurs, avis) utilise une clausewhere
pour définir les critères spécifiques de la recherche.
Intégrer des requêtes dans l'application Web
- Dans
MovieService
(app/src/lib/MovieService.tsx
), désactivez la mise en commentaire des importations suivantes:
import { searchAll, SearchAllData } from "@movie/dataconnect";
- Remplacez la fonction
handleSearchAll
par le code suivant:
// Function to perform the search using the query and filters
export const handleSearchAll = async (
searchQuery: string,
minYear: number,
maxYear: number,
minRating: number,
maxRating: number,
genre: string
): Promise<SearchAllData | null> => {
try {
const response = await searchAll({
input: searchQuery,
minYear,
maxYear,
minRating,
maxRating,
genre,
});
return response.data;
} catch (error) {
console.error("Error performing search:", error);
return null;
}
};
Points à retenir :
handleSearchAll
: cette fonction utilise la requêtesearchAll
pour effectuer une recherche en fonction de l'entrée de l'utilisateur, en filtrant les résultats en fonction de paramètres tels que l'année, la note, le genre et les correspondances textuelles partielles.
Voir une démo
Accédez à la page "Recherche avancée" depuis la barre de navigation de l'application Web. Vous pouvez désormais rechercher des films, des acteurs et des avis à l'aide de divers filtres et entrées, et obtenir des résultats de recherche détaillés et personnalisés.
9. Facultatif: Déployer dans le cloud (facturation requise)
Maintenant que vous avez terminé l'itération de développement local, il est temps de déployer votre schéma, vos données et vos requêtes sur le serveur. Pour ce faire, utilisez l'extension VS Code Firebase Data Connect ou la CLI Firebase.
Ajouter une application Web dans la console Firebase
- Créez une application Web dans la console Firebase et notez son ID d'application.
- Configurez une application Web dans la console Firebase en cliquant sur "Ajouter une application". Vous pouvez ignorer la configuration du SDK pour le moment, mais notez l'objet
firebaseConfig
généré. - Remplacez
firebaseConfig
dansapp/src/lib/firebase.tsx
:
const firebaseConfig = { apiKey: "API_KEY", authDomain: "PROJECT_ID.firebaseapp.com", projectId: "PROJECT_ID", storageBucket: "PROJECT_ID.appspot.com", messagingSenderId: "SENDER_ID", appId: "APP_ID" };
- Créez l'application Web:dans le dossier
app
, utilisez Vite pour créer l'application Web à des fins de déploiement d'hébergement:
cd app npm run build
Configurer Firebase Authentication dans la console
- Configurer Firebase Auth avec Google Sign-In
- (Facultatif) Autorisez les domaines pour (Firebase Auth) [https://firebase.google.com/docs/auth/web/hosting] dans la console de votre projet (par exemple,
http://127.0.0.1
):
- Dans les paramètres Auth, sélectionnez votre projet, puis accédez à (Domaines autorisés) [https://firebase.google.com/docs/auth/web/hosting]. Cliquez sur "Ajouter un domaine" et ajoutez votre domaine local à la liste.
Déployer avec la CLI Firebase
- Dans
dataconnect/dataconnect.yaml
, assurez-vous que votre ID d'instance, de base de données et de service correspondent à votre projet:
specVersion: "v1alpha" serviceId: "your-service-id" location: "us-central1" schema: source: "./schema" datasource: postgresql: database: "your-database-id" cloudSql: instanceId: "your-instance-id" connectorDirs: ["./movie-connector"]
- Assurez-vous que la CLI Firebase est configurée avec votre projet.
npm i -g firebase-tools
firebase login --reauth
firebase use --add
- Dans votre terminal, exécutez la commande suivante pour le déployer:
firebase deploy --only dataconnect,hosting
- Exécutez cette commande pour comparer les modifications apportées à votre schéma:
firebase dataconnect:sql:diff
- Si les modifications sont acceptables, appliquez-les avec:
firebase dataconnect:sql:migrate
Votre instance Cloud SQL pour PostgreSQL sera mise à jour avec le schéma et les données déployés. Vous pouvez surveiller l'état dans la console Firebase.
Vous devriez maintenant pouvoir voir votre application en direct sur your-project.web.app/
. Vous pouvez également cliquer sur Run (Production) (Exécuter (Production)) dans le panneau Firebase Data Connect, comme vous l'avez fait avec les émulateurs locaux, pour ajouter des données à l'environnement de production.
10. (Facultatif) Recherche vectorielle avec Firebase Data Connect
Dans cette section, vous allez activer la recherche vectorielle dans votre application de critiques de films à l'aide de Firebase Data Connect. Cette fonctionnalité permet d'effectuer des recherches basées sur le contenu, par exemple pour trouver des films dont les descriptions sont similaires à l'aide d'embeddings vectoriels.
Mettre à jour le schéma pour inclure des représentations vectorielles continues pour un champ
- Dans
dataconnect/schema/schema.gql
, ajoutez le champdescriptionEmbedding
au tableauMovie
:
type Movie
# The below parameter values are generated by default with @table, and can be edited manually.
@table {
# implicitly calls @col to generates a column name. ex: @col(name: "movie_id")
id: UUID! @default(expr: "uuidV4()")
title: String!
imageUrl: String!
releaseYear: Int
genre: String
rating: Float
description: String
tags: [String]
descriptionEmbedding: Vector @col(size:768) # Enables vector search
}
Points à retenir :
descriptionEmbedding: Vector @col(size:768)
: ce champ stocke les représentations vectorielles continues sémantiques des descriptions de films, ce qui permet de rechercher du contenu basé sur des vecteurs dans votre application.
Activer Vertex AI
- Suivez le guide des prérequis pour configurer les API Vertex AI avec Google Cloud. Cette étape est essentielle pour prendre en charge la génération d'embeddings et la fonctionnalité de recherche vectorielle.
- Redéployez votre schéma pour activer
pgvector
et la recherche vectorielle en cliquant sur "Deploy to Production" (Déployer en production) à l'aide de l'extension VSCode Firebase Data Connect.
Insérer des représentations vectorielles continues dans la base de données
- Ouvrez le dossier
dataconnect
dans VS Code, puis cliquez sur Run(local) (Exécuter (local)) dansoptional_vector_embed.gql
pour renseigner votre base de données avec des représentations vectorielles continues pour les films.
Ajouter une requête Vector Search
- Dans
dataconnect/movie-connector/queries.gql
, ajoutez la requête suivante pour effectuer des recherches vectorielles:
# Search movie descriptions using L2 similarity with Vertex AI
query SearchMovieDescriptionUsingL2Similarity($query: String!)
@auth(level: PUBLIC) {
movies_descriptionEmbedding_similarity(
compare_embed: { model: "textembedding-gecko@003", text: $query }
method: L2
within: 2
limit: 5
) {
id
title
description
tags
rating
imageUrl
}
}
Points à retenir :
compare_embed
: spécifie le modèle d'embedding (textembedding-gecko@003
) et le texte d'entrée ($query
) à comparer.method
: spécifie la méthode de similarité (L2
), qui représente la distance euclidienne.within
: limite la recherche aux films dont la distance L2 est de 2 ou moins, en se concentrant sur les correspondances de contenu proches.limit
: limite le nombre de résultats renvoyés à cinq.
Implémenter la fonction Vector Search dans l'application
- Dans
app/src/lib/MovieService.ts
, annulez la mise en commentaire des importations suivantes:
Implémenter la fonction de recherche vectorielle dans l'application
Maintenant que le schéma et la requête sont configurés, intégrez la recherche vectorielle dans la couche de service de votre application. Cette étape vous permet d'appeler la requête de recherche à partir de votre application Web.
Dans app/src/lib/
MovieService.ts
, désactivez la mise en commentaire des importations suivantes à partir des SDK. Cela fonctionnera comme n'importe quelle autre requête.
import {
searchMovieDescriptionUsingL2similarity,
SearchMovieDescriptionUsingL2similarityData,
} from "@movie/dataconnect";
Ajoutez la fonction suivante pour intégrer la recherche vectorielle à l'application:
// Perform vector-based search for movies based on description
export const searchMoviesByDescription = async (
query: string
): Promise<
| SearchMovieDescriptionUsingL2similarityData["movies_descriptionEmbedding_similarity"]
| null
> => {
try {
const response = await searchMovieDescriptionUsingL2similarity({ query });
return response.data.movies_descriptionEmbedding_similarity;
} catch (error) {
console.error("Error fetching movie descriptions:", error);
return null;
}
};
Points à retenir :
searchMoviesByDescription
: cette fonction appelle la requêtesearchMovieDescriptionUsingL2similarity
, en transmettant le texte saisi pour effectuer une recherche de contenu basée sur des vecteurs.
Voir une démo
Accédez à la section "Recherche vectorielle" dans la barre de navigation, puis saisissez des expressions telles que "romantique et moderne". Vous verrez une liste de films correspondant au contenu que vous recherchez. Vous pouvez également accéder à la page d'informations d'un film et consulter la section "Films similaires" en bas de la page.
11. Conclusion
Félicitations, vous devriez pouvoir utiliser l'application Web. Si vous souhaitez utiliser vos propres données de films, n'hésitez pas à insérer vos propres données à l'aide de l'extension FDC en imitant les fichiers _insert.gql, ou à les ajouter via le volet d'exécution de Data Connect.