1. Présentation
Cet atelier de programmation vous explique comment intégrer Firebase Data Connect à une base de données Cloud SQL pour créer une application d'avis sur les films pour iOS à l'aide de SwiftUI.
Vous allez apprendre à connecter votre application iOS à une base de données Cloud SQL à l'aide de Firebase Data Connect, ce qui vous permettra de synchroniser facilement les données des critiques de films.
À la fin de cet atelier de programmation, vous disposerez d'une application iOS fonctionnelle qui permettra aux utilisateurs de parcourir des films et de les marquer comme favoris, le tout reposant sur une base de données Cloud SQL utilisant la puissance de Firebase Data Connect.
Points abordés
Cet atelier de programmation vous apprendra à:
- Configurez Firebase Data Connect à l'aide de la suite Firebase Emulator pour obtenir des résultats rapides.
- Concevez un schéma de base de données à l'aide de Data Connect et de GraphQL.
- Créez un SDK Swift sécurisé à partir de votre schéma de base de données et ajoutez-le à une application Swift.
- Implémentez l'authentification des utilisateurs et intégrez-la à Firebase Data Connect pour sécuriser les données de vos utilisateurs.
- Récupérez, mettez à jour, supprimez et gérez des données dans Cloud SQL à l'aide de requêtes et de mutations optimisées par GraphQL.
- (Facultatif) Déployez un service Data Connect en production.
Prérequis
- La dernière version de Xcode
- Exemple de code de l'atelier de programmation Vous téléchargerez l'exemple de code lors de l'une des premières étapes de l'atelier de programmation.
2. Configurer l'exemple de projet
Créer un projet Firebase
- Connectez-vous à la console Firebase avec votre compte Google.
- Dans la console Firebase, cliquez sur Créer un projet Firebase.
- Nommez votre projet Firebase (par exemple, "Friendly Flix"), puis cliquez sur Continuer.
- Vous pouvez être invité à activer l'assistance IA pour votre projet Firebase. Pour les besoins de cet atelier de programmation, votre sélection n'a pas d'importance.
- Vous serez peut-être invité à activer Google Analytics. Pour les besoins de cet atelier de programmation, votre sélection n'a pas d'importance.
- Au bout d'une minute environ, votre projet Firebase sera prêt. Cliquez sur Continuer.
Télécharger le code
Exécutez la commande suivante pour cloner l'exemple de code de cet atelier de programmation. Un répertoire nommé codelab-dataconnect-ios
est alors créé sur votre machine:
git clone https://github.com/peterfriese/codelab-dataconnect-ios`
Si vous ne disposez pas de git sur votre ordinateur, vous pouvez également télécharger le code directement depuis GitHub.
Ajouter la configuration Firebase
Le SDK Firebase utilise un fichier de configuration pour se connecter à votre projet Firebase. Sur les plates-formes Apple, ce fichier est appelé GoogleServices-Info.plist
. Au cours de cette étape, vous allez télécharger le fichier de configuration et l'ajouter à votre projet Xcode.
- Dans la console Firebase, sélectionnez Vue d'ensemble du projet dans le panneau de navigation de gauche.
- Cliquez sur le bouton iOS+ pour sélectionner la plate-forme. Lorsque vous êtes invité à saisir l'ID de groupe Apple, utilisez
com.google.firebase.samples.FriendlyFlix
. - Cliquez sur Enregistrer l'application, puis suivez les instructions pour télécharger le fichier
GoogleServices-Info.plist
. - Déplacez le fichier téléchargé dans le répertoire
start/FriendlyFlix/app/FriendlyFlix/FriendlyFlix/
du code que vous venez de télécharger, en remplaçant le fichierGoogleServices-Info.plist
existant. - Cliquez ensuite plusieurs fois sur Suivant pour terminer le projet de configuration dans la console Firebase. Vous n'avez pas besoin d'ajouter le SDK à l'application, car cela a déjà été fait dans le projet de démarrage.
- Enfin, cliquez sur Continue to console (Accéder à la console) pour terminer le processus de configuration.
3. Configurer Data Connect
Installation
Installation automatique
Exécutez la commande suivante dans le répertoire codelab-dataconnect-ios/FriendlyFlix
:
curl -sL https://firebase.tools/dataconnect | bash
Ce script tente de configurer l'environnement de développement pour vous et de lancer un IDE intégré au navigateur. Cet IDE fournit des outils, y compris une extension VS Code préemballée, pour vous aider à gérer votre schéma, à définir les requêtes et les mutations à utiliser dans votre application, et à générer des SDK fortement typés.
Une fois le script exécuté, VS Code devrait s'ouvrir automatiquement.
Une fois cette opération effectuée, vous pouvez démarrer VS Code en exécutant VS Code dans le répertoire local:
code .
Installation manuelle
- Installer Visual Studio Code
- Installez Node.js.
- Dans VS Code, ouvrez le répertoire
codelab-dataconnect-ios/FriendlyFlix
. - Installez l'extension Firebase Data Connect depuis Visual Studio Code Marketplace.
Initialiser Data Connect dans le projet
Dans le panneau de gauche, cliquez sur l'icône Firebase pour ouvrir l'interface utilisateur de l'extension VS Code Data Connect.
- Cliquez sur le bouton Se connecter avec Google. Une fenêtre de navigateur s'ouvre. Suivez les instructions pour vous connecter à l'extension avec votre compte Google.
- Cliquez sur le bouton Connecter un projet Firebase, puis sélectionnez le projet que vous avez créé précédemment dans la console.
- Cliquez sur le bouton Run firebase init (Exécuter firebase init), puis suivez les étapes dans le terminal intégré.
Configurer la génération du SDK
Une fois que vous avez cliqué sur le bouton Run firebase init (Exécuter firebase init), l'extension Firebase Data Connect doit initialiser un répertoire dataconnect
pour vous.
Dans VS Code, ouvrez le fichier dataconnect/connector/connector.yaml
pour afficher la configuration par défaut.
Veuillez mettre à jour la configuration et utiliser les paramètres suivants pour vous assurer que le code généré fonctionne avec cet atelier de programmation. Plus précisément, assurez-vous que connectorId
est défini sur friendly-flix
et le package Swift sur FriendlyFlixSDK
.
connectorId: "friendly-flix"
generate:
swiftSdk:
outputDir: "../../app"
package: "FriendlyFlixSDK"
observablePublisher: observableMacro
Voici la signification de ces paramètres:
connectorId
: nom unique de ce connecteur.outputDir
: chemin d'accès où le SDK Data Connect généré sera stocké. Ce chemin d'accès est relatif au répertoire contenant le fichierconnector.yaml
.package
: nom du package à utiliser pour le package Swift généré.
Une fois ce fichier enregistré, Firebase Data Connect génère un package Swift nommé FriendlyFlixSDK
et le place à côté du dossier de projet FriendlyFlix
.
Démarrer les émulateurs Firebase
Dans VS Code, basculez dans la vue Firebase, puis cliquez sur le bouton Démarrer les émulateurs.
L'émulateur Firebase se lance dans le terminal intégré. Le résultat doit se présenter comme suit :
npx -y firebase-tools@latest emulators:start --project <your-project-id>
Ajouter le package généré à votre application Swift
- Ouvrir
FriendlyFlix/app/FriendlyFlix/FriendlyFlix.xcodeproj
dans Xcode - Sélectionnez File > Add Package Dependencies (Fichier > Ajouter des dépendances de package).
- Cliquez sur Ajouter un établissement, puis ajoutez le package
FriendlyFlixSDK
à partir du dossierFriendlyFlix/app
. - Attendez que Xcode résolve les dépendances de paquets.
- Dans la boîte de dialogue Choose Package Products for FriendlyFlixSDK (Choisir des produits de package pour FriendlyFlixSDK), sélectionnez
FriendlyFlix
comme cible, puis cliquez sur Add Package (Ajouter un package).
Configurer l'application iOS pour qu'elle utilise l'émulateur local
- Ouvrez
FriendlyFlixApp.swift
. (Vous pouvez appuyer sur CMD+Maj+O pour ouvrir la boîte de dialogue Ouvrir rapidement, puis saisir "FriendlyFlixApp" pour trouver rapidement le fichier.) - Importer Firebase, Firebase Auth, Firebase Data Connect et le SDK généré pour votre schéma
- Dans l'initialiseur, configurez Firebase.
- Assurez-vous que DataConnect et Firebase Authentication utilisent l'émulateur local.
import SwiftUI
import os
import Firebase
import FirebaseAuth
import FriendlyFlixSDK
import FirebaseDataConnect
@main
struct FriendlyFlixApp: App {
...
init() {
FirebaseApp.configure()
if useEmulator {
DataConnect.friendlyFlixConnector.useEmulator(port: 9399)
Auth.auth().useEmulator(withHost: "localhost", port: 9099)
}
authenticationService = AuthenticationService()
}
...
}
- Sélectionnez un simulateur iOS dans le menu déroulant Destination.
- Appuyez sur CMD+R (ou cliquez sur le bouton Run (Exécuter)) dans Xcode pour exécuter l'application sur un simulateur.
4. Définir le schéma et préremplir la base de données
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
, MovieMetaData
et d'autres 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.
Entités et relations principales
Le modèle de données de cette application de suivi de films se compose de plusieurs entités que vous allez créer au cours de cet atelier de programmation. Vous commencerez par créer les entités principales, puis, à mesure que vous implémenterez de plus en plus de fonctionnalités, vous ajouterez les entités requises pour ces fonctionnalités.
À cette étape, vous allez créer les types Movie
et MovieMetadata
.
Film
Le type Movie
définit la structure principale d'une entité de film, y compris des champs tels que title
, genre
, releaseYear
et rating
.
Dans VS Code, ajoutez la définition de type Movie
à 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]
}
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.
Ajoutez la définition de la table MovieMetadata
au fichier dataconnect/schema/schema.gql
:
type MovieMetadata @table {
movie: Movie! @ref
director: String
}
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 id
du type Movie
est automatiquement renseigné par un UUID lorsqu'un nouvel enregistrement est créé.
Insérer des données fictives pour les films et les métadonnées des films
Une fois le schéma défini, vous pouvez préremplir la base de données avec des données fictives à des fins de test.
- Dans le Finder, copiez
finish/FriendlyFlix/dataconnect/moviedata_insert.gql
dans le dossierstart/FriendlyFlix/dataconnect
. - 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 dans le terminal Data Connect Execution (Exécution de la connexion aux données) que les données ont bien été ajoutées.
Une fois les données en place, passez à l'étape suivante pour découvrir comment créer des requêtes dans Data Connect.
5. Récupérer et afficher des films
Dans cette section, vous allez implémenter une fonctionnalité permettant d'afficher une liste de films.
Vous allez d'abord apprendre à créer une requête qui récupère tous les films de la table movies
. Firebase Data Connect génère du code pour un SDK sécurisé par type que vous pouvez ensuite utiliser pour exécuter la requête et afficher les films récupérés dans l'interface utilisateur de votre application.
Définir la requête ListMovies
Les requêtes dans Firebase Data Connect sont écrites en GraphQL, ce qui vous permet de spécifier les champs à extraire. Dans FriendlyFlix, les écrans qui affichent des films nécessitent les champs suivants: title
, description
, releaseYear
, rating
et imageUrl
. De plus, comme il s'agit d'une application SwiftUI, vous aurez besoin de id
pour gérer l'identité de la vue SwiftUI.
Dans VS Code, ouvrez le fichier dataconnect/connector/queries.gql
et ajoutez la requête ListMovies
:
query ListMovies @auth(level: PUBLIC) {
movies {
id
title
imageUrl
releaseYear
genre
rating
tags
description
}
}
Pour tester la nouvelle requête, cliquez sur le bouton Run (local) (Exécuter (local)) pour l'exécuter sur votre base de données locale. La liste des films de la base de données doit s'afficher dans la section Résultats du terminal d'exécution Data Connect.
Associer la requête ListMovies à l'écran d'accueil de l'application
Maintenant que vous avez testé la requête dans l'émulateur Data Connect, vous pouvez l'appeler depuis votre application.
Lorsque vous enregistrez queries.gql
, Firebase Data Connect génère le code correspondant à la requête ListMovies
dans le package FriendlyFlixSDK
.
Dans Xcode, ouvrez Movie+DataConnect.swift
, puis ajoutez le code suivant pour mapper ListMoviesQuery.Data.Movie
sur Movie
:
import FirebaseDataConnect
import FriendlyFlixSDK
extension Movie {
init(from: ListMoviesQuery.Data.Movie) {
id = from.id
title = from.title
description = from.description ?? ""
releaseYear = from.releaseYear
rating = from.rating
imageUrl = from.imageUrl
}
}
Ouvrez le fichier HomeScreen.swift
et mettez-le à jour à l'aide de l'extrait de code suivant.
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK
struct HomeScreen: View {
...
private var connector = DataConnect.friendlyFlixConnector
let heroMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>
init() {
heroMoviesRef = connector.listMoviesQuery.ref()
}
}
extension HomeScreen {
...
private var heroMovies: [Movie] {
heroMoviesRef.data?.movies.map(Movie.init) ?? []
}
private var topMovies: [Movie] {
heroMoviesRef.data?.movies.map(Movie.init) ?? []
}
private var watchList: [Movie] {
heroMoviesRef.data?.movies.map(Movie.init) ?? []
}
...
}
La requête |
Exécuter l'application
Dans Xcode, cliquez sur le bouton Run (Exécuter) pour lancer l'application dans le simulateur iOS.
Une fois l'application lancée, un écran semblable à celui-ci s'affiche:
Vous remarquerez peut-être que toutes les sections de l'application (la section "Hero", les meilleurs films et la liste de lecture) affichent la même liste. En effet, vous utilisez la même requête pour toutes ces vues. Dans les sections suivantes, vous allez implémenter des requêtes personnalisées. |
6. Afficher le héros et les meilleurs films
À cette étape, vous allez modifier la façon dont les films sont affichés dans la section "Hero" (c'est-à-dire le carrousel proéminent en haut de l'écran d'accueil), ainsi que dans la section "Top des films" ci-dessous.
Actuellement, la requête ListMovies récupère tous les films. Pour optimiser l'affichage de ces sections, vous devez limiter le nombre de films renvoyés par chaque requête. L'implémentation actuelle de la requête ListMovies
n'offre pas encore de prise en charge intégrée de la limitation des résultats. Vous allez ajouter la prise en charge de la limitation et de l'ordre dans cette section.
Améliorer la requête ListMovies
Ouvrez queries.gql
et mettez à jour ListMovies
comme suit pour ajouter la prise en charge de l'ordre et de la limite:
query ListMovies(
$orderByRating: OrderDirection
$orderByReleaseYear: OrderDirection
$limit: Int
) @auth(level: PUBLIC) {
movies(
orderBy: [{ rating: $orderByRating }, { releaseYear: $orderByReleaseYear }]
limit: $limit
) {
id
title
description
releaseYear
rating
imageUrl
}
}
Vous pourrez ainsi limiter le nombre de films renvoyés par la requête et trier l'ensemble de résultats par note et par année de sortie.
Une fois ce fichier enregistré, Firebase Data Connect regénère automatiquement le code dans FriendlyFlixSDK
. À l'étape suivante, vous pouvez modifier le code dans HomeScreen.swift
pour utiliser ces fonctionnalités supplémentaires.
Utiliser la requête améliorée dans l'UI
Revenez à Xcode pour apporter les modifications requises à HomeScreen.swift
.
Commencez par mettre à jour heroMoviesRef
pour récupérer les trois derniers films sortis:
struct HomeScreen {
...
init() {
heroMoviesRef = connector.listMoviesQuery
.ref { optionalVars in
optionalVars.limit = 3
optionalVars.orderByReleaseYear = .DESC
}
}
}
Ensuite, configurez une autre référence de requête pour les meilleurs films et définissez le filtre sur les cinq films les mieux notés:
struct HomeScreen {
...
let topMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>
init() {
heroMoviesRef = ...
topMoviesRef = connector.listMoviesQuery
.ref { optionalVars in
optionalVars.limit = 5
optionalVars.orderByRating = .DESC
}
}
}
Enfin, mettez à jour la propriété calculée qui associe le résultat de cette requête à l'UI:
extension HomeScreen {
...
private var topMovies: [Movie] {
topMoviesRef.data?.movies.map(Movie.init) ?? []
}
}
Démonstration
Exécutez à nouveau l'application pour afficher les trois films les plus récents dans la section "Hero" (Aperçu) et les cinq films les mieux notés dans la section "Top movies" (Meilleurs films) :
7. Afficher les détails du film et des acteurs
L'utilisateur peut maintenant parcourir les films. Lorsque vous appuyez sur une fiche de film, vous obtenez des informations à son sujet, mais vous avez peut-être remarqué qu'elles manquaient de détails.
En effet, nous n'avons récupéré que les informations nécessaires pour afficher la section "Hero" et la section "Top des films" : le titre du film, une courte description et l'URL de l'image.
Sur la page d'informations du film, nous souhaitons afficher plus d'informations à son sujet. Dans cette section, vous allez améliorer l'application afin qu'elle puisse afficher les acteurs du film et les avis sur la page d'informations.
Pour ce faire, vous devez effectuer quelques opérations:
- Amélioration du schéma pour prendre en charge les acteurs et les critiques de films
- Écrire des requêtes Firebase Data Connect pour extraire des informations sur un film donné
- Affichage des résultats sur l'écran d'informations du film
Améliorer le schéma
Dans VS Code, ouvrez dataconnect/schema/schema.gql
et ajoutez les définitions de schéma pour Actor
et MovieActor
.
## Actors
## An actor can participate in multiple movies; movies can have multiple actors
## Movie - Actors (or vice versa) is a many to many relationship
type Actor @table {
id: UUID!
imageUrl: String!
name: String! @col(name: "name", dataType: "varchar(30)")
}
## Join table for many-to-many relationship for movies and actors
## The 'key' param signifies the primary key(s) of this table
## In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor]
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"
}
Ajouter des données fictives pour les acteurs
Une fois le schéma mis à jour, vous pouvez insérer d'autres données fictives dans la base de données à des fins de test.
- Dans le Finder, copiez
finish/FriendlyFlix/dataconnect/moviededetails_insert.gql
dans le dossierstart/FriendlyFlix/dataconnect
. - Dans VS Code, ouvrez
dataconnect/moviededetails_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 dans le terminal d'exécution de Data Connect que les données ont bien été ajoutées.
Une fois les données en place, passez à l'étape suivante pour définir la requête permettant d'extraire les détails du film.
Définir la requête GetMovieById
Dans VS Code, ouvrez le fichier dataconnect/connector/queries.gql
et ajoutez la requête GetMovieById
:
## 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
}
}
}
Connecter la requête GetMovieById à MovieDetailsView
Dans Xcode, ouvrez le fichier MovieDetailsView.swift
et mettez à jour la propriété calculée movieDetails
pour qu'elle corresponde au code suivant:
import NukeUI
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK
@MainActor
struct MovieDetailsView: View {
private var movie: Movie
private var movieDetails: MovieDetails? {
DataConnect.friendlyFlixConnector
.getMovieByIdQuery
.ref(id: movie.id)
.data?.movie.map { movieDetails in
MovieDetails(
title: movieDetails.title,
description: movieDetails.description ?? "",
releaseYear: movieDetails.releaseYear,
rating: movieDetails.rating ?? 0,
imageUrl: movieDetails.imageUrl,
mainActors: movieDetails.mainActors.map { mainActor in
MovieActor(id: mainActor.id,
name: mainActor.name,
imageUrl: mainActor.imageUrl)
},
supportingActors: movieDetails.supportingActors.map{ supportingActor in
MovieActor(id: supportingActor.id,
name: supportingActor.name,
imageUrl: supportingActor.imageUrl)
},
reviews: []
)
}
}
public init(movie: Movie) {
self.movie = movie
}
}
Exécuter l'application
Dans Xcode, cliquez sur le bouton Run (Exécuter) pour lancer l'application sur l'émulateur iOS.
Une fois l'application lancée, appuyez sur une fiche de film pour afficher ses détails. Elle devrait se présenter comme ceci :
8. Implémenter l'authentification des utilisateurs
Actuellement, l'application présente des informations non personnalisées sur les films et les acteurs. Dans les étapes suivantes, vous allez implémenter des fonctionnalités qui associent des données à l'utilisateur connecté. Vous commencerez par autoriser les utilisateurs à ajouter des films à leur liste de visionnage personnelle.
Avant de pouvoir implémenter la fonctionnalité de liste de lecture, vous devez d'abord établir l'identité de l'utilisateur. Pour ce faire, vous allez intégrer Firebase Authentication, ce qui permettra aux utilisateurs de se connecter à l'application.
Vous avez peut-être déjà remarqué le bouton de l'avatar utilisateur en haut à droite de l'écran d'accueil. Si vous appuyez dessus, vous accédez à un écran sur lequel les utilisateurs peuvent s'inscrire ou se connecter avec leur adresse e-mail et leur mot de passe.
Une fois qu'un utilisateur s'est connecté, votre application doit stocker ses informations essentielles, en particulier son ID utilisateur unique et le nom d'utilisateur qu'il a choisi.
Activer Firebase Authentication
Dans la console Firebase de votre projet, accédez à la section "Authentification" et activez Firebase Authentication. Activez ensuite le fournisseur d'authentification par adresse e-mail/mot de passe.
Dans le dossier de votre projet local, recherchez firebase.json
et mettez-le à jour comme suit pour activer l'émulateur Firebase Authentication.
{
"emulators": {
"dataconnect": {
},
"auth": {
}
},
"dataconnect": {
"source": "dataconnect"
}
}
Vous devez ensuite arrêter et redémarrer Firebase Emulator pour que la modification prenne effet.
Implémenter un gestionnaire d'authentification
Dans la section suivante, vous allez implémenter la logique qui relie l'authentification des utilisateurs à votre base de données. Pour ce faire, vous devez créer un gestionnaire d'authentification qui écoute les connexions réussies.
Une fois qu'un utilisateur est authentifié, ce gestionnaire déclenche automatiquement la création de son compte correspondant dans votre base de données.
Dans Xcode, ouvrez le fichier AuthenticationService.swift
et ajoutez le code suivant:
import Foundation
import Observation
import os
import FirebaseAuth
enum AuthenticationState {
case unauthenticated
case authenticating
case authenticated
}
@Observable
class AuthenticationService {
private let logger = Logger(subsystem: "FriendlyFlix", category: "auth")
var presentingAuthenticationDialog = false
var presentingAccountDialog = false
var authenticationState: AuthenticationState = .unauthenticated
var user: User?
private var authenticationListener: AuthStateDidChangeListenerHandle?
init() {
authenticationListener = Auth.auth().addStateDidChangeListener { auth, user in
if let user {
self.authenticationState = .authenticated
self.user = user
} else {
self.authenticationState = .unauthenticated
}
}
}
private var onSignUp: ((User) -> Void)?
public func onSignUp(_ action: @escaping (User) -> Void) {
onSignUp = action
}
func signInWithEmailPassword(email: String, password: String) async throws {
try await Auth.auth().signIn(withEmail: email, password: password)
authenticationState = .authenticated
}
func signUpWithEmailPassword(email: String, password: String) async throws {
try await Auth.auth().createUser(withEmail: email, password: password)
if let onSignUp, let user = Auth.auth().currentUser {
logger
.debug(
"User signed in \(user.displayName ?? "(no fullname)") with email \(user.email ?? "(no email)")"
)
onSignUp(user)
}
authenticationState = .authenticated
}
func signOut() throws {
try Auth.auth().signOut()
authenticationState = .unauthenticated
}
}
Il s'agit d'un gestionnaire d'authentification générique qui vous permet d'utiliser onSignUp
pour enregistrer une fermeture qui sera appelée lorsque l'utilisateur se sera connecté.
Dans cette clôture, vous pouvez ensuite créer un compte utilisateur dans la base de données. Mais avant de pouvoir le faire, vous devez créer une mutation qui vous permet de créer ou de mettre à jour des utilisateurs dans la base de données.
Ajouter une entité "Utilisateur" au schéma
Le type User
définit une entité utilisateur. Les utilisateurs peuvent interagir avec les films en laissant des avis ou en les ajoutant à leurs favoris.
Dans VS Code, ouvrez le fichier dataconnect/schema/schema.gql
et ajoutez la définition de table User
suivante:
## Users
## A user can leave reviews for movies
## user-reviews is a one to many relationship, movie-reviews is a one to many relationship, movie:user is a many to many relationship
type User @table {
id: String! @col(name: "user_auth")
username: String! @col(name: "username", dataType: "varchar(50)")
}
Définir une mutation pour insérer ou mettre à jour un utilisateur
Dans VS Code, ouvrez le fichier dataconnect/connector/mutations.gql
et ajoutez la mutation UpsertUser
:
mutation UpsertUser($username: String!) @auth(level: USER) {
user_upsert(
data: {
id_expr: "auth.uid"
username: $username
}
)
}
Créer un utilisateur après une connexion réussie
Dans Xcode, ouvrez FriendlyFlixApp.swift
, puis ajoutez le code suivant à l'initialiseur:
@main
struct FriendlyFlixApp: App {
...
init() {
...
authenticationService = AuthenticationService()
authenticationService?.onSignUp { user in
let userName = String(user.email?.split(separator: "@").first ?? "(unknown)")
Task {
try await DataConnect.friendlyFlixConnector
.upsertUserMutation.execute(username: userName)
}
}
}
var body: some Scene {
...
}
}
Ce code utilise l'upsertUserMutation
Firebase Data Connect généré pour vous afin d'insérer un nouvel utilisateur (ou de mettre à jour un utilisateur existant avec le même ID) chaque fois qu'un utilisateur s'est inscrit avec Firebase Authentication.
Démonstration
Pour vérifier que cela fonctionne, commencez par vous inscrire dans l'application iOS:
- Si ce n'est pas le cas, arrêtez et redémarrez l'émulateur Firebase pour vous assurer que l'émulateur Firebase Authentication est en cours d'exécution.
- Dans Xcode, cliquez sur le bouton Run (Exécuter) pour lancer l'application sur l'émulateur iOS.
- Cliquez sur l'icône de l'avatar en haut à droite de l'écran.
- Accédez au parcours S'inscrire et inscrivez-vous à l'application.
Interrogez ensuite la base de données pour vérifier que l'application a créé un compte utilisateur pour l'utilisateur:
- Dans VS Code, ouvrez
dataconnect/schema/schema.gql
, puis cliquez sur Lire les données sur l'entitéUser
. - Un fichier de requête nommé
User_read.gql
est créé. - Cliquez sur Exécuter en local pour afficher tous les utilisateurs dans le tableau des utilisateurs.
- Dans le volet "Exécution de Data Connect", vous devriez maintenant voir un compte pour l'utilisateur avec lequel vous venez de vous inscrire :
9. Gérer les films préférés
Dans cette section de l'atelier de programmation, vous allez implémenter des interactions utilisateur dans l'application d'avis sur les films, en particulier pour permettre aux utilisateurs de gérer leurs films préférés. Les films marqués comme favoris s'affichent dans la section "Liste de lecture" de l'application.
Améliorer le schéma pour prendre en charge les favoris
Le type FavoriteMovie
est une table de jointure qui gère les relations plusieurs à plusieurs entre les utilisateurs et leurs films préférés. Chaque table lie un User
à un Movie
.
Copiez et collez l'extrait de code suivant 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!
}
Définir des mutations pour ajouter et supprimer des favoris
Avant que l'application puisse afficher les films préférés de l'utilisateur, celui-ci doit indiquer lesquels sont ses favoris. Pour ce faire, vous devez d'abord ajouter deux mutations pour marquer un film comme l'un des favoris de l'utilisateur ou le supprimer de ses favoris.
- Dans VS Code, ouvrez
mutations.gql
dansdataconnect/connector/mutations.gql
. - 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 })
}
Associer les mutations à l'UI de votre application
Les utilisateurs peuvent ajouter un film à leurs favoris en cliquant sur l'icône en forme de cœur sur l'écran d'informations du film.
Pour associer les mutations que vous venez de créer à l'UI de l'application, apportez les modifications suivantes dans MovieCardView
:
- Importer le
FriendlyFlixSDK
et configurer le connecteur
import NukeUI
import os
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK
struct MovieCardView: View {
private let logger = Logger(subsystem: "FriendlyFlix", category: "moviecard")
@Environment(\.dismiss) private var dismiss
private var connector = DataConnect.friendlyFlixConnector
...
}
- Implémentez la méthode
toggleFavourite
. Il est appelé chaque fois que l'utilisateur appuie sur l'icône en forme de cœur dansMovieCardView
:
struct MovieCardView {
...
private func toggleFavourite() {
Task {
if isFavourite {
let _ = try await connector.deleteFavoritedMovieMutation.execute(movieId: movie.id)
} else {
let _ = try await connector.addFavoritedMovieMutation.execute(movieId: movie.id)
}
}
}
}
L'état "favori" du film en cours est alors mis à jour dans la base de données. Une dernière étape est manquante : vous devez vous assurer que l'état de l'UI est reflété en conséquence.
Définir une requête pour déterminer si un film est marqué comme favori
- Dans VS Code, ouvrez
queries.gql
dansdataconnect/connector
. - Ajoutez la requête suivante pour vérifier si un film est marqué comme favori:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
movieId
}
}
- Dans Xcode, instanciez une référence à la requête
GetIfFavoritedMovie
et implémentez la propriété calculée qui détermine si le film affiché sur cetteMovieCardView
est marqué comme favori pour l'utilisateur actuel.
struct MovieCardView: View {
...
public init(showDetails: Bool, movie: Movie) {
self.showDetails = showDetails
self.movie = movie
isFavouriteRef = connector.getIfFavoritedMovieQuery.ref(movieId: movie.id)
}
// MARK: - Favourite handling
private let isFavouriteRef: QueryRefObservation<
GetIfFavoritedMovieQuery.Data,
GetIfFavoritedMovieQuery.Variables
>
private var isFavourite: Bool {
isFavouriteRef.data?.favorite_movie?.movieId != nil
}
...
}
- Modifiez le code dans
toggleFavourite
pour exécuter la requête chaque fois que l'utilisateur appuie sur le bouton. Cela garantit que la propriété calculéeisFavourite
renvoie toujours la valeur correcte.
private func toggleFavourite() {
Task {
if isFavourite {
...
}
let _ = try await isFavouriteRef.execute()
}
}
Récupérer les films préférés
Pour terminer cette fonctionnalité, vous allez récupérer les films préférés de l'utilisateur afin qu'il puisse les voir dans sa liste de lecture.
- Dans VS Code, ouvrez
queries.gql
dansdataconnect/connector/queries.gql
et collez la requête suivante:
## Get favorite movies by user ID
query GetUserFavoriteMovies @auth(level: USER) {
user(id_expr: "auth.uid") {
favoriteMovies: favorite_movies_on_user {
movie {
id
title
genre
imageUrl
releaseYear
rating
description
}
}
}
}
La liste des films préférés de l'utilisateur s'affiche dans LibraryScreen
. Cet écran ne doit afficher des données que si l'utilisateur est connecté. Vous devez donc d'abord associer l'état d'authentification de l'écran à l'AuthenticationService
de l'application.
- Ajoutez du code pour mapper un
FavoriteMovieFavoriteMovies
à unMovie
, puis à unMovie+DataConnect.swift
:
import FirebaseDataConnect
import FriendlyFlixSDK
extension Movie {
...
init(from: GetUserFavoriteMoviesQuery.Data.User.FavoriteMovieFavoriteMovies) {
id = from.movie.id
title = from.movie.title
description = from.movie.description ?? ""
releaseYear = from.movie.releaseYear
rating = from.movie.rating
imageUrl = from.movie.imageUrl
}
}
- Dans Xcode, ouvrez
LibraryScreen
, puis mettez à jourisSignedIn
comme suit:
struct LibraryScreen: View {
...
private var isSignedIn: Bool {
authenticationService.user != nil
}
}
- Importez ensuite Firebase Data Connect et FriendlyFlixSDK, puis obtenez une référence à la requête
GetUserFavoriteMovies
:
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK
struct LibraryScreen {
...
private var connector = DataConnect.friendlyFlixConnector
...
init() {
watchListRef = connector.getUserFavoriteMoviesQuery.ref()
}
private let watchListRef: QueryRefObservation<
GetUserFavoriteMoviesQuery.Data,
GetUserFavoriteMoviesQuery.Variables
>
private var watchList: [Movie] {
watchListRef.data?.user?.favoriteMovies.map(Movie.init) ?? []
}
...
}
- Assurez-vous que la requête
watchListRef
est exécutée lorsque la vue s'affiche:
extension LibraryScreen: View {
var body: some View {
...
MovieListSection(namespace: namespace, title: "Watch List", movies: watchList)
.onAppear {
Task {
try await watchListRef.execute()
}
...
Démonstration
Vous pouvez maintenant exécuter l'application et tester la fonctionnalité "Favoris" que vous venez d'implémenter. Voici quelques points à retenir:
- Assurez-vous que l'émulateur Firebase est en cours d'exécution
- Assurez-vous d'avoir ajouté des données fictives pour les films et les informations les concernant.
- Assurez-vous d'être inscrit en tant qu'utilisateur.
- Dans Xcode, cliquez sur le bouton Run (Exécuter) pour lancer l'application sur l'émulateur iOS.
- Une fois l'application lancée, appuyez sur une fiche de film pour afficher ses détails.
- Appuyez sur l'icône en forme de cœur pour ajouter le film à vos favoris. Le cœur doit devenir plein.
- Répétez cette opération pour quelques films.
- Accédez à l'onglet "Bibliothèque". La liste de tous les films que vous avez marqués comme favoris devrait s'afficher.
10. Félicitations
Félicitations, vous avez bien ajouté Firebase Data Connect à une application iOS. Vous connaissez maintenant les étapes clés requises pour configurer Data Connect, créer des requêtes et des mutations, et gérer l'authentification des utilisateurs.
(Facultatif) Déployer en production
Jusqu'à présent, cette application n'a utilisé que les émulateurs Firebase. Si vous souhaitez découvrir comment déployer cette application dans un véritable projet Firebase, passez à l'étape suivante.
11. (Facultatif) Déployer votre application
Jusqu'à présent, cette application était entièrement locale. Toutes les données sont contenues dans la suite d'émulateurs Firebase. Dans cette section, vous allez apprendre à configurer votre projet Firebase pour que cette application fonctionne en production.
Activer Firebase Authentication
- Dans la console Firebase, accédez à la section Authentication (Authentification) et cliquez sur Get started (Premiers pas).
- Accédez à l'onglet Mode de connexion .
- Sélectionnez l'option "Adresse e-mail/Mot de passe" dans la section "Fournisseurs natifs".
- Activez le fournisseur "Adresse e-mail/Mot de passe", puis cliquez sur Enregistrer.
Activer Firebase Data Connect
Important: Si vous déployez un schéma pour la première fois dans votre projet, ce processus crée une instance PostgreSQL Cloud SQL, ce qui peut prendre environ 15 minutes. Vous ne pourrez pas effectuer de déploiement tant que l'instance Cloud SQL n'est pas prête et intégrée à Firebase Data Connect.
1. Dans l'interface utilisateur de l'extension VS Code Firebase Data Connect, cliquez sur Deploy to production (Déployer en production). 2. Vous devrez peut-être examiner les modifications de schéma et approuver les modifications potentiellement destructrices. Vous serez invité à: - examiner les modifications apportées au schéma à l'aide de firebase dataconnect:sql:diff
; - une fois que les modifications vous conviennent, les appliquer à l'aide du flux lancé par 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 pouvez maintenant cliquer sur "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.
Avant d'exécuter à nouveau l'application iOS, assurez-vous qu'elle se connecte à l'instance de production de votre projet:
- Ouvrez le menu Product > Scheme > Edit Scheme… (Produit > Schéma > Modifier le schéma…).
- Dans la section Exécuter, décochez l'argument de lancement
-useEmulator YES
.