1. Descripción general
En este codelab, se te guiará por el proceso de integración de Firebase Data Connect con una base de datos de Cloud SQL para compilar una app de opiniones de películas para iOS con SwiftUI.
Aprenderás a conectar tu aplicación para iOS a una base de datos de Cloud SQL con Firebase Data Connect, lo que te permitirá sincronizar datos sin interrupciones para las opiniones de películas.
Al final de este codelab, tendrás una app para iOS funcional que permitirá a los usuarios explorar películas y marcarlas como favoritas, todo respaldado por una base de datos de Cloud SQL con la potencia de Firebase Data Connect.
Qué aprenderás
En este codelab, aprenderás a hacer lo siguiente:
- Configura Firebase Data Connect con el paquete de Firebase Emulator para obtener tiempos de respuesta rápidos.
- Diseña un esquema de base de datos con Data Connect y GraphQL.
- Crea un SDK de Swift seguro de tipos a partir del esquema de tu base de datos y agrégalo a una aplicación de Swift.
- Implementa la autenticación de usuarios y intégrala con Firebase Data Connect para proteger los datos de tus usuarios.
- Recupera, actualiza, borra y administra datos en Cloud SQL con consultas y mutaciones potenciadas por GraphQL.
- (Opcional) Implementa un servicio de Data Connect en producción.
Requisitos previos
- La versión más reciente de Xcode
- El código de muestra del codelab Descargarás el código de muestra en uno de los primeros pasos del codelab.
2. Configura el proyecto de ejemplo
Crea un proyecto de Firebase
- Accede a Firebase console con tu Cuenta de Google.
- En Firebase console, haz clic en Create a Firebase project.
- Ingresa un nombre para tu proyecto de Firebase (por ejemplo, "Friendly Flix") y haz clic en Continuar.
- Es posible que se te solicite que habilites la asistencia de IA para tu proyecto de Firebase. Para los fines de este codelab, tu selección no importa.
- Es posible que se te solicite habilitar Google Analytics. Para los fines de este codelab, tu selección no importa.
- Después de un minuto aproximadamente, tu proyecto de Firebase estará listo. Haz clic en Continuar.
Descarga el código
Ejecuta el siguiente comando para clonar el código de muestra de este codelab. Esto creará un directorio llamado codelab-dataconnect-ios
en tu máquina:
git clone https://github.com/FirebaseExtended/codelab-dataconnect-ios`
Si no tienes git en tu máquina, también puedes descargar el código directamente desde GitHub.
Agrega la configuración de Firebase
El SDK de Firebase usa un archivo de configuración para conectarse a tu proyecto de Firebase. En las plataformas de Apple, este archivo se llama GoogleServices-Info.plist
. En este paso, descargarás el archivo de configuración y lo agregarás a tu proyecto de Xcode.
- En Firebase console, selecciona Descripción general del proyecto en el panel de navegación izquierdo.
- Haz clic en el botón iOS+ para seleccionar la plataforma. Cuando se te solicite el ID del paquete de Apple, usa
com.google.firebase.samples.FriendlyFlix
. - Haz clic en Registrar app y sigue las instrucciones para descargar el archivo
GoogleServices-Info.plist
. - Mueve el archivo descargado al directorio
start/FriendlyFlix/app/FriendlyFlix/FriendlyFlix/
del código que acabas de descargar y reemplaza el archivoGoogleServices-Info.plist
existente. - Luego, haz clic en Siguiente un par de veces para completar el proyecto de configuración en Firebase console (no es necesario que agregues el SDK a la app, ya que esto ya se realizó en el proyecto de partida).
- Por último, haz clic en Ir a la consola para finalizar el proceso de configuración.
3. Configura Data Connect
Instalación
Instalación automática
Ejecuta el siguiente comando en el directorio codelab-dataconnect-ios/FriendlyFlix
:
curl -sL https://firebase.tools/dataconnect | bash
Esta secuencia de comandos intenta configurar el entorno de desarrollo por ti y, luego, iniciar un IDE basado en el navegador. Este IDE proporciona herramientas, incluida una extensión precompilada de VS Code, para ayudarte a administrar tu esquema y definir las consultas y mutaciones que se usarán en tu aplicación, y generar SDKs con tipado estricto.
Después de ejecutar la secuencia de comandos, VS Code debería abrirse automáticamente.
Después de hacerlo una vez, puedes iniciar VS Code ejecutando VS Code en el directorio local:
code .
Instalación manual
- Instala Visual Studio Code
- Instala Node.js.
- En VS Code, abre el directorio
codelab-dataconnect-ios/FriendlyFlix
. - Instala la extensión de Firebase Data Connect desde Visual Studio Code Marketplace.
Inicializa Data Connect en el proyecto
En el panel izquierdo, haz clic en el ícono de Firebase para abrir la IU de la extensión de VS Code de Data Connect.
- Haz clic en el botón Acceder con Google. Se abrirá una ventana del navegador. Sigue las instrucciones para acceder a la extensión con tu Cuenta de Google.
- Haz clic en el botón Connect a Firebase project y selecciona el proyecto que creaste antes en la consola.
- Haz clic en el botón Run firebase init y sigue los pasos que se indican en la terminal integrada.
Configura la generación de SDK
Una vez que hagas clic en el botón Run firebase init, la extensión de Firebase Data Connect debería inicializar un directorio dataconnect
por ti.
En VS Code, abre el archivo dataconnect/connector/connector.yaml
y encontrarás la configuración predeterminada.
Actualiza la configuración y usa la siguiente configuración para asegurarte de que el código generado funcione con este codelab. En particular, asegúrate de que connectorId
esté configurado como friendly-flix
y el paquete de Swift como FriendlyFlixSDK
.
connectorId: "friendly-flix"
generate:
swiftSdk:
outputDir: "../../app"
package: "FriendlyFlixSDK"
observablePublisher: observableMacro
Estos son los significados de estos parámetros de configuración:
connectorId
: Es un nombre único para este conector.outputDir
: Es la ruta de acceso en la que se almacenará el SDK de Data Connect generado. Esta ruta de acceso es relativa al directorio que contiene el archivoconnector.yaml
.package
: Es el nombre del paquete que se usará para el paquete Swift generado.
Una vez que guardes este archivo, Firebase Data Connect generará un paquete Swift llamado FriendlyFlixSDK
y lo colocará junto a la carpeta del proyecto FriendlyFlix
.
Inicia los emuladores de Firebase
En VS Code, cambia a la vista de Firebase y, luego, haz clic en el botón Iniciar emuladores.
Esto iniciará el emulador de Firebase en la terminal integrada. El resultado debería verse así:
npx -y firebase-tools@latest emulators:start --project <your-project-id>
Agrega el paquete generado a tu app para Swift
- Cómo abrir
FriendlyFlix/app/FriendlyFlix/FriendlyFlix.xcodeproj
en Xcode - Selecciona File > Add Package Dependencies….
- Haz clic en Add Local… y, luego, agrega el paquete
FriendlyFlixSDK
de la carpetaFriendlyFlix/app
. - Espera a que Xcode resuelva las dependencias del paquete.
- En el diálogo Choose Package Products for FriendlyFlixSDK, selecciona
FriendlyFlix
como destino y haz clic en Add Package.
Configura la app para iOS para usar el emulador local
- Abre
FriendlyFlixApp.swift
. (Puedes presionar CMD + Mayúsculas + O para abrir el diálogo Abrir rápido y, luego, escribir "FriendlyFlixApp" para encontrar el archivo rápidamente). - Importa Firebase, Firebase Auth, Firebase Data Connect y el SDK generado para tu esquema
- En el inicializador, configura Firebase.
- Asegúrate de que DataConnect y Firebase Auth usen el emulador 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()
}
...
}
- Selecciona un simulador de iOS en el menú desplegable Destino.
- Presiona CMD + R (o haz clic en el botón Run) en Xcode para ejecutar la app en un simulador.
4. Define el esquema y prepropaga la base de datos
En esta sección, definirás la estructura y las relaciones entre las entidades clave de la aplicación de películas en un esquema. Las entidades como Movie
, MovieMetaData
y otras se asignan a tablas de bases de datos, con relaciones establecidas mediante Firebase Data Connect y directivas de esquemas de GraphQL.
Entidades y relaciones principales
El modelo de datos de esta app de seguimiento de películas consta de varias entidades que crearás a lo largo de este codelab. Primero, crearás las entidades principales y, a medida que implementes más y más funciones, agregarás las entidades necesarias para esas funciones.
En este paso, crearás los tipos Movie
y MovieMetadata
.
Película
El tipo Movie
define la estructura principal de una entidad de película, incluidos campos como title
, genre
, releaseYear
y rating
.
En VS Code, agrega la definición de tipo Movie
a 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
El tipo MovieMetadata
establece una relación de uno a uno con el tipo Movie
. Incluye datos adicionales, como el director de la película.
Agrega la definición de la tabla MovieMetadata
al archivo dataconnect/schema/schema.gql
:
type MovieMetadata @table {
movie: Movie! @ref
director: String
}
Campos y valores predeterminados generados automáticamente
El esquema usa expresiones como @default(expr: "uuidV4()")
para generar automáticamente IDs y marcas de tiempo únicos. Por ejemplo, el campo id
en el tipo Movie
se completa automáticamente con un UUID cuando se crea un registro nuevo.
Cómo insertar datos simulados para películas y metadatos de películas
Con el esquema definido, ahora puedes prepropagar la base de datos con datos simulados para realizar pruebas.
- En Finder, copia
finish/FriendlyFlix/dataconnect/moviedata_insert.gql
en la carpetastart/FriendlyFlix/dataconnect
. - En VS Code, abre
dataconnect/moviedata_insert.gql
. - Asegúrate de que los emuladores de la extensión de Firebase Data Connect estén en ejecución.
- Deberías ver un botón Run (local) en la parte superior del archivo. Haz clic en este botón para insertar los datos de películas simuladas en tu base de datos.
- Verifica la terminal Data Connect Execution para confirmar que los datos se hayan agregado correctamente.
Con los datos en su lugar, continúa con el siguiente paso para aprender a crear consultas en Data Connect.
5. Cómo recuperar y mostrar películas
En esta sección, implementarás una función para mostrar una lista de películas.
Primero, aprenderás a crear una consulta que recupere todas las películas de la tabla movies
. Firebase Data Connect genera código para un SDK seguro de tipos que puedes usar para ejecutar la consulta y mostrar las películas recuperadas en la IU de tu app.
Define la consulta ListMovies
Las consultas en Firebase Data Connect se escriben en GraphQL, lo que te permite especificar qué campos recuperar. En FriendlyFlix, las pantallas que muestran películas requieren los siguientes campos: title
, description
, releaseYear
, rating
y imageUrl
. Además, como se trata de una app de SwiftUI, necesitarás id
para ayudar con la identidad de la vista de SwiftUI.
En VS Code, abre el archivo dataconnect/connector/queries.gql
y agrega la consulta ListMovies
:
query ListMovies @auth(level: PUBLIC) {
movies {
id
title
imageUrl
releaseYear
genre
rating
tags
description
}
}
Para probar la nueva consulta, haz clic en el botón Run (local) para ejecutarla en tu base de datos local. La lista de películas de la base de datos debería mostrarse en la sección Resultados de la terminal de ejecución de Data Connect.
Conecta la consulta ListMovies a la pantalla principal de la app
Ahora que probaste la consulta en el emulador de Data Connect, puedes llamarla desde tu app.
Cuando guardas queries.gql
, Firebase Data Connect genera el código correspondiente a la consulta ListMovies
en el paquete FriendlyFlixSDK
.
En Xcode, abre Movie+DataConnect.swift
y agrega el siguiente código para asignar de ListMoviesQuery.Data.Movie
a 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
}
}
Abre el archivo HomeScreen.swift
y actualízalo con el siguiente fragmento de código.
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) ?? []
}
...
}
Data Connect generó la consulta |
Ejecuta la app
En Xcode, haz clic en el botón Run para iniciar la app en el simulador de iOS.
Una vez que se inicie la app, deberías ver una pantalla como esta:
Es posible que notes que todas las áreas de la app (la sección principal, las películas principales y la lista de reproducción) muestran la misma lista. Esto se debe a que usas la misma consulta para todas esas vistas. En las siguientes secciones, implementarás consultas personalizadas. |
6. Cómo mostrar películas principales y de portada
En este paso, te enfocarás en actualizar la forma en que se muestran las películas en la sección hero (el carrusel destacado en la parte superior de la pantalla principal) y también en la sección de películas principales que aparece debajo.
Actualmente, la consulta ListMovies recupera todas las películas. Para optimizar la visualización de estas secciones, limita la cantidad de películas que muestra cada consulta. La implementación actual de la consulta ListMovies
aún no ofrece compatibilidad integrada para limitar los resultados. En esta sección, agregarás compatibilidad para limitar y ordenar.
Mejora la consulta ListMovies
Abre queries.gql
y actualiza ListMovies
de la siguiente manera para agregar compatibilidad con el ordenamiento y la limitación:
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
}
}
Esto te permitirá limitar la cantidad de películas que muestra la consulta y ordenar el conjunto de resultados por calificación y año de lanzamiento.
Una vez que guardes este archivo, Firebase Data Connect volverá a generar automáticamente el código en FriendlyFlixSDK
. En el siguiente paso, puedes actualizar el código en HomeScreen.swift
para usar estas funciones adicionales.
Usa la consulta mejorada en la IU
Regresa a Xcode para realizar los cambios necesarios en HomeScreen.swift
.
Primero, actualiza heroMoviesRef
para recuperar las 3 películas estrenadas más recientemente:
struct HomeScreen {
...
init() {
heroMoviesRef = connector.listMoviesQuery
.ref { optionalVars in
optionalVars.limit = 3
optionalVars.orderByReleaseYear = .DESC
}
}
}
A continuación, configura otra referencia de consulta para las películas principales y establece el filtro en las 5 películas con la calificación más alta:
struct HomeScreen {
...
let topMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>
init() {
heroMoviesRef = ...
topMoviesRef = connector.listMoviesQuery
.ref { optionalVars in
optionalVars.limit = 5
optionalVars.orderByRating = .DESC
}
}
}
Por último, actualiza la propiedad calculada que conecta el resultado de esta consulta a la IU:
extension HomeScreen {
...
private var topMovies: [Movie] {
topMoviesRef.data?.movies.map(Movie.init) ?? []
}
}
Míralo en acción
Vuelve a ejecutar la app para ver las 3 películas más recientes en la sección Hero y las 5 películas con la calificación más alta en la sección Top movies:
7. Cómo mostrar detalles de películas y actores
Ahora el usuario puede explorar películas. Cuando presiones la tarjeta de una película, se mostrarán algunos detalles sobre ella, pero es posible que hayas notado que les falta cierta cantidad de… bueno, detalles.
Esto se debe a que solo recuperamos tantos detalles sobre cada película como necesitábamos para renderizar la sección de héroe de la película y la sección de películas principales: el título de la película, una descripción breve y la URL de la imagen.
En la página de detalles de la película, queremos mostrar más información sobre ella. En esta sección, mejorarás la app para que pueda mostrar los actores de la película y las opiniones en la página de detalles.
Para ello, deberás hacer lo siguiente:
- Mejora el esquema para admitir actores y opiniones de películas
- Escribe consultas de Firebase Data Connect para recuperar detalles sobre una película determinada
- Cómo mostrar los resultados en la pantalla de detalles de la película
Mejora el esquema
En VS Code, abre dataconnect/schema/schema.gql
y agrega las definiciones de esquemas para Actor
y 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"
}
Agrega datos simulados para los actores
Con el esquema actualizado, ahora puedes completar la base de datos con más datos simulados para realizar pruebas.
- En Finder, copia
finish/FriendlyFlix/dataconnect/moviededetails_insert.gql
en la carpetastart/FriendlyFlix/dataconnect
. - En VS Code, abre
dataconnect/moviededetails_insert.gql
. - Asegúrate de que los emuladores de la extensión de Firebase Data Connect estén en ejecución.
- Deberías ver un botón Run (local) en la parte superior del archivo. Haz clic en este botón para insertar los datos de películas simuladas en tu base de datos.
- Revisa la terminal de ejecución de Data Connect para confirmar que los datos se hayan agregado correctamente.
Con los datos en su lugar, continúa con el siguiente paso para definir la consulta que recuperará los detalles de la película.
Define la consulta GetMovieById
En VS Code, abre el archivo dataconnect/connector/queries.gql
y agrega la consulta 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
}
}
}
Conecta la consulta GetMovieById a MovieDetailsView
En Xcode, abre el archivo MovieDetailsView.swift
y actualiza la propiedad calculada movieDetails
para que coincida con el siguiente código:
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
}
}
Ejecuta la app
En Xcode, haz clic en el botón Run para iniciar la app en el simulador de iOS.
Una vez que se inicie la app, presiona la tarjeta de una película para mostrar sus detalles. Se verá de la siguiente manera:
8. Implementa la autenticación de usuarios
Actualmente, la app presenta información no personalizada de películas y actores. En los siguientes pasos, implementarás funciones que asocien datos con el usuario que accedió. Para comenzar, permitirás que los usuarios agreguen películas a su lista para ver personal.
Antes de implementar la función de lista de seguimiento, primero debes establecer la identidad del usuario. Para habilitar esta función, integrarás Firebase Authentication, lo que permitirá que los usuarios accedan a la app.
Es posible que ya hayas visto el botón del avatar de usuario en la parte superior derecha de la pantalla principal. Si presionas esta opción, se te dirigirá a una pantalla en la que los usuarios pueden registrarse o acceder con su correo electrónico y contraseña.
Una vez que un usuario acceda correctamente, tu app deberá almacenar sus detalles esenciales, principalmente su ID de usuario único y el nombre de usuario elegido.
Habilita Firebase Authentication
En Firebase console de tu proyecto, ve a la sección Authentication y habilita Firebase Authentication. Luego, habilita el proveedor de autenticación de correo electrónico y contraseña.
En la carpeta de tu proyecto local, busca firebase.json
y actualízalo de la siguiente manera para habilitar el emulador de Firebase Authentication.
{
"emulators": {
"dataconnect": {
},
"auth": {
}
},
"dataconnect": {
"source": "dataconnect"
}
}
Después de esto, debes detener y reiniciar Firebase Emulator para que se aplique el cambio.
Implementa un controlador de autenticación
En la siguiente sección, implementarás la lógica que conecta la autenticación del usuario con tu base de datos. Esto implica crear un controlador de autenticación que escuche los accesos exitosos.
Una vez que se autentica un usuario, este controlador activará automáticamente la creación de su cuenta correspondiente en tu base de datos.
En Xcode, abre el archivo AuthenticationService.swift
y agrega el siguiente código:
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
}
}
Este es un controlador de autenticación genérico que te permite usar onSignUp
para registrar un cierre al que se llamará cuando el usuario haya accedido.
Dentro de ese cierre, puedes crear una cuenta de usuario nueva en la base de datos. Sin embargo, antes de hacerlo, debes crear una mutación que te permita crear o actualizar usuarios nuevos en la base de datos.
Agrega una entidad de usuario al esquema
El tipo User
define una entidad de usuario. Los usuarios pueden interactuar con las películas dejando opiniones o agregándolas a favoritos.
En VS Code, abre el archivo dataconnect/schema/schema.gql
y agrega la siguiente definición de tabla User
:
## 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)")
}
Define una mutación para insertar o actualizar un usuario
En VS Code, abre el archivo dataconnect/connector/mutations.gql
y agrega la mutación UpsertUser
:
mutation UpsertUser($username: String!) @auth(level: USER) {
user_upsert(
data: {
id_expr: "auth.uid"
username: $username
}
)
}
Crea un usuario nuevo después de acceder correctamente
En Xcode, abre FriendlyFlixApp.swift
y agrega el siguiente código al inicializador:
@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 {
...
}
}
Este código usa el objeto upsertUserMutation
de Firebase Data Connect que se generó para que insertes un usuario nuevo (o actualices un usuario existente con el mismo ID) cada vez que un usuario se registre correctamente con Firebase Authentication.
Míralo en acción
Para verificar que esto funcione, primero regístrate en la app para iOS:
- Si aún no lo has hecho, detén y reinicia Firebase Emulator para asegurarte de que el emulador de Firebase Authentication esté en ejecución.
- En Xcode, haz clic en el botón Run para iniciar la app en el simulador de iOS.
- Haz clic en el ícono de avatar que se encuentra en la esquina superior derecha de la pantalla.
- Cambia al flujo de Registro y regístrate en la app.
Luego, consulta la base de datos para verificar que la app haya creado una cuenta de usuario nueva para el usuario:
- En VS Code, abre
dataconnect/schema/schema.gql
y haz clic en Read data en la entidadUser
. - Se creará un nuevo archivo de consulta llamado
User_read.gql
. - Haz clic en Run local para ver todos los usuarios en la tabla de usuarios.
- En el panel de ejecución de Data Connect, ahora deberías ver una cuenta para el usuario con el que te registraste
9. Cómo administrar películas favoritas
En esta sección del codelab, implementarás interacciones del usuario en la app de opiniones de películas, lo que les permitirá a los usuarios administrar sus películas favoritas. Las películas marcadas como favoritas aparecerán en la sección de la lista para ver de la app.
Mejora el esquema para admitir favoritos
El tipo FavoriteMovie
es una tabla de unión que controla las relaciones varios a varios entre los usuarios y sus películas favoritas. Cada tabla vincula un User
a un Movie
.
Copia y pega el fragmento de código en tu archivo 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!
}
Define mutaciones para agregar y quitar favoritos
Antes de que la app pueda mostrar las películas favoritas del usuario, este debe indicar cuáles son sus favoritas. Para lograrlo, primero debes agregar dos mutaciones para marcar una película como una de las favoritas del usuario o quitarla de sus favoritos, respectivamente.
- En VS Code, abre
mutations.gql
endataconnect/connector/mutations.gql
. - Agrega las siguientes mutaciones para controlar las películas favoritas:
## 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 })
}
Conecta las mutaciones a la IU de tu app
Los usuarios pueden marcar una película como favorita haciendo clic en el ícono de corazón en la pantalla de detalles de la película.
Para conectar las mutaciones que acabas de crear a la IU de la app, realiza los siguientes cambios en MovieCardView
:
- Importa el
FriendlyFlixSDK
y configura el conector
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
...
}
- Implementa el método
toggleFavourite
. Se llamará cada vez que el usuario presione el ícono de corazón enMovieCardView
:
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)
}
}
}
}
Se actualizará el estado de favorito de la película actual en la base de datos. Falta un último paso para asegurarse de que el estado de la IU se refleje de manera adecuada.
Define una consulta para averiguar si una película está marcada como favorita
- En VS Code, abre
queries.gql
endataconnect/connector
. - Agrega la siguiente consulta para verificar si una película está marcada como favorita:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
movieId
}
}
- En Xcode, crea una instancia de una referencia a la consulta
GetIfFavoritedMovie
y, luego, implementa la propiedad calculada que determina si la película que se muestra en esteMovieCardView
está marcada como favorita para el usuario actual.
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
}
...
}
- Actualiza el código en
toggleFavourite
para ejecutar la consulta cada vez que el usuario presione el botón. Esto garantiza que la propiedad calculadaisFavourite
siempre muestre el valor correcto.
private func toggleFavourite() {
Task {
if isFavourite {
...
}
let _ = try await isFavouriteRef.execute()
}
}
Cómo recuperar películas favoritas
Como paso final de esta función, implementarás la recuperación de las películas favoritas del usuario para que pueda verlas en su lista de reproducción.
- En VS Code, abre
queries.gql
endataconnect/connector/queries.gql
y pega la siguiente consulta:
## 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 lista de películas favoritas del usuario se muestra en LibraryScreen
. Esta pantalla solo debe mostrar datos si el usuario accedió, por lo que primero debes conectar el estado de autenticación de la pantalla al AuthenticationService
de la app.
- Agrega código para asignar de
FavoriteMovieFavoriteMovies
aMovie
aMovie+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
}
}
- En Xcode, abre
LibraryScreen
y, luego, actualizaisSignedIn
de la siguiente manera:
struct LibraryScreen: View {
...
private var isSignedIn: Bool {
authenticationService.user != nil
}
}
- Luego, importa Firebase Data Connect y FriendlyFlixSDK, y obtén una referencia a la consulta
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) ?? []
}
...
}
- Asegúrate de que se ejecute la consulta
watchListRef
cuando aparezca la vista:
extension LibraryScreen: View {
var body: some View {
...
MovieListSection(namespace: namespace, title: "Watch List", movies: watchList)
.onAppear {
Task {
try await watchListRef.execute()
}
...
Míralo en acción
Ahora puedes ejecutar la app y probar la función de favoritos que acabas de implementar. Ten en cuenta lo siguiente:
- Asegúrate de que el emulador de Firebase esté en ejecución
- Asegúrate de haber agregado datos simulados para las películas y sus detalles.
- Asegúrate de haberte registrado como usuario
- En Xcode, haz clic en el botón Run para iniciar la app en el simulador de iOS.
- Una vez que se inicie la app, presiona la tarjeta de una película para mostrar sus detalles.
- Presiona el ícono de corazón para marcar la película como favorita. El corazón debe volverse sólido.
- Repite este proceso para un par de películas.
- Ve a la pestaña Biblioteca. Ahora deberías ver una lista de todas las películas que marcaste como favoritas.
10. Felicitaciones
¡Felicitaciones! Agregaste correctamente Firebase Data Connect a una app para iOS. Ahora conoces los pasos clave necesarios para configurar Data Connect, crear consultas y mutaciones, y controlar la autenticación de usuarios.
Opcional: Implementa en producción
Hasta ahora, esta app solo usó los emuladores de Firebase. Si quieres aprender a implementar esta app en un proyecto real de Firebase, continúa con el siguiente paso.
11. Implementa tu app (opcional)
Hasta ahora, esta app ha sido completamente local, y todos los datos se encuentran en Firebase Local Emulator Suite. En esta sección, aprenderás a configurar tu proyecto de Firebase para que esta app funcione en producción.
Habilita Firebase Authentication
- En Firebase console, ve a la sección Authentication y haz clic en Comenzar.
- Navega a la pestaña Método de acceso .
- Selecciona la opción Correo electrónico/Contraseña en la sección de proveedores nativos.
- Habilita el proveedor de correo electrónico o contraseña y, luego, haz clic en Guardar.
Habilita Firebase Data Connect
Importante: Si es la primera vez que implementas un esquema en tu proyecto, este proceso creará una instancia de PostgreSQL de Cloud SQL, lo que puede tardar alrededor de 15 minutos. No podrás realizar la implementación hasta que la instancia de Cloud SQL esté lista y esté integrada con Firebase Data Connect.
1. En la IU de la extensión de VS Code de Firebase Data Connect, haz clic en Deploy to production. 2. Es posible que debas revisar los cambios de esquema y aprobar las modificaciones potencialmente destructivas. Se te pedirá que hagas lo siguiente: - Revisa los cambios en el esquema con firebase dataconnect:sql:diff
. - Cuando estés conforme con los cambios, aplícalos con el flujo que inició firebase dataconnect:sql:migrate
.
Tu instancia de Cloud SQL para PostgreSQL se actualizará con el esquema y los datos finales que se hayan implementado. Puedes supervisar el estado en Firebase console.
Ahora puedes hacer clic en Ejecutar (producción) en el panel de Firebase Data Connect, tal como lo hiciste con los emuladores locales, para agregar datos al entorno de producción.
Antes de volver a ejecutar la app para iOS, asegúrate de que se conecte a la instancia de producción de tu proyecto:
- Abre el menú Product > Scheme > Edit Scheme….
- En la sección Run, desmarca el argumento de inicio
-useEmulator YES
.