Criar com o Firebase Data Connect (iOS / Swift)

1. Visão geral

Este codelab orienta você no processo de integração do Firebase Data Connect com um banco de dados do Cloud SQL para criar um app de avaliação de filmes para iOS usando o SwiftUI.

Você vai aprender a conectar seu aplicativo iOS a um banco de dados do Cloud SQL usando o Firebase Data Connect, permitindo a sincronização de dados perfeita para avaliações de filmes.

Ao final deste codelab, você terá um app iOS funcional que permite aos usuários navegar por filmes e marcá-los como favoritos, tudo com o suporte de um banco de dados do Cloud SQL usando o poder do Firebase Data Connect.

O que você vai aprender

Neste codelab, você vai aprender a:

  • Configure o Firebase Data Connect usando o pacote de emuladores do Firebase para tempos de resposta rápidos.
  • Projete um esquema de banco de dados usando o Data Connect e o GraphQL.
  • Crie um SDK Swift typesafe com base no esquema do banco de dados e adicione-o a um aplicativo Swift.
  • Implemente a autenticação de usuários e integre-a ao Firebase Data Connect para proteger os dados dos usuários.
  • Recupere, atualize, exclua e gerencie dados no Cloud SQL usando consultas e mutações com tecnologia do GraphQL.
  • (Opcional) Implante um serviço do Data Connect na produção.

Pré-requisitos

  • A versão mais recente do Xcode
  • O exemplo de código do codelab. Você vai fazer o download do exemplo de código em uma das primeiras etapas do codelab.

2. Configurar o projeto de amostra

Criar um projeto do Firebase

  1. Faça login no console do Firebase usando sua Conta do Google.
  2. Clique no botão para criar um projeto e insira um nome (por exemplo, Friendly Flix).
  3. Clique em Continuar.
  4. Se solicitado, leia e aceite os Termos do Firebase e clique em Continuar.
  5. (Opcional) Ative a assistência de IA no console do Firebase (chamada de "Gemini no Firebase").
  6. Neste codelab, você não precisa do Google Analytics. Portanto, desative a opção do Google Analytics.
  7. Clique em Criar projeto, aguarde o provisionamento e clique em Continuar.

Fazer o download do código

Execute o comando a seguir para clonar o código de amostra deste codelab. Isso vai criar um diretório chamado codelab-dataconnect-ios na sua máquina:

git clone https://github.com/FirebaseExtended/codelab-dataconnect-ios`

Se você não tiver o git na sua máquina, também poderá fazer o download do código diretamente do GitHub.

Adicionar configuração do Firebase

O SDK do Firebase usa um arquivo de configuração para se conectar ao seu projeto do Firebase. Em plataformas Apple, esse arquivo é chamado de GoogleServices-Info.plist. Nesta etapa, você vai baixar o arquivo de configuração e adicioná-lo ao projeto do Xcode.

  1. No console do Firebase, selecione Visão geral do projeto no menu de navegação à esquerda.
  2. Clique no botão iOS+ para selecionar a plataforma. Quando o ID do pacote da Apple for solicitado, use com.google.firebase.samples.FriendlyFlix.
  3. Clique em Registrar app e siga as instruções para fazer o download do arquivo GoogleServices-Info.plist.
  4. Mova o arquivo baixado para o diretório start/FriendlyFlix/app/FriendlyFlix/FriendlyFlix/ do código que você acabou de baixar, substituindo o arquivo GoogleServices-Info.plist atual.
  5. Em seguida, clique em Próxima algumas vezes para concluir o projeto de configuração no console do Firebase. Não é necessário adicionar o SDK ao app, já que isso já foi feito no projeto inicial.
  6. Por fim, clique em Continuar para o console para concluir o processo de configuração.

3. Configurar o Data Connect

Instalação

Instalação automática

Execute o seguinte comando no diretório codelab-dataconnect-ios/FriendlyFlix:

curl -sL https://firebase.tools/dataconnect | bash

Esse script tenta configurar o ambiente de desenvolvimento para você e iniciar um IDE baseado em navegador. Esse ambiente de desenvolvimento integrado oferece ferramentas, incluindo uma extensão do VS Code pré-agrupada, para ajudar você a gerenciar seu esquema e definir consultas e mutações a serem usadas no aplicativo, além de gerar SDKs fortemente tipados.

Depois de executar o script, o VS Code vai abrir automaticamente.

Depois de fazer isso uma vez, você pode iniciar o VS Code executando-o no diretório local:

code .

Instalação manual

  1. Instalar o Visual Studio Code
  2. Instale o Node.js.
  3. No VS Code, abra o diretório codelab-dataconnect-ios/FriendlyFlix.
  4. Instale a extensão do Firebase Data Connect no Visual Studio Code Marketplace.

Inicializar o Data Connect no projeto

No painel à esquerda, clique no ícone do Firebase para abrir a interface da extensão Data Connect VS Code.

  1. Clique no botão Fazer login com o Google. Uma janela do navegador será aberta. Siga as instruções para fazer login na extensão com sua Conta do Google.
  2. Clique no botão Conectar um projeto do Firebase e selecione o projeto que você criou antes no console.
  3. Clique no botão Executar firebase init e siga as etapas no terminal integrado.

Configurar a geração do SDK

Depois de clicar no botão Executar firebase init, a extensão Firebase Data Connect vai inicializar um diretório dataconnect para você.

No VS Code, abra o arquivo dataconnect/connector/connector.yaml para encontrar a configuração padrão.

Atualize a configuração e use as seguintes configurações para garantir que o código gerado funcione com este codelab. Especificamente, verifique se connectorId está definido como friendly-flix e o pacote Swift como FriendlyFlixSDK.

connectorId: "friendly-flix"
generate:
  swiftSdk:
    outputDir: "../../app"
    package: "FriendlyFlixSDK"
    observablePublisher: observableMacro

Confira o que essas configurações significam:

  • connectorId: um nome exclusivo para o conector.
  • outputDir: caminho em que o SDK do Data Connect gerado será armazenado. Esse caminho é relativo ao diretório que contém o arquivo connector.yaml.
  • package: o nome do pacote a ser usado para o pacote Swift gerado.

Depois de salvar esse arquivo, o Firebase Data Connect vai gerar um pacote Swift chamado FriendlyFlixSDK e colocá-lo ao lado da pasta do projeto FriendlyFlix.

Iniciar os emuladores do Firebase

No VS Code, mude para a visualização do Firebase e clique no botão Iniciar emuladores.

Isso vai iniciar o Firebase Emulator no terminal integrado. O resultado será semelhante a este:

npx -y firebase-tools@latest emulators:start --project <your-project-id>

Adicionar o pacote gerado ao seu app Swift

  1. Abrir FriendlyFlix/app/FriendlyFlix/FriendlyFlix.xcodeproj no Xcode
  2. Selecione Arquivo > Adicionar dependências de pacote…
  3. Clique em Adicionar local... e adicione o pacote FriendlyFlixSDK da pasta FriendlyFlix/app.
  4. Aguarde o Xcode resolver as dependências do pacote.
  5. Na caixa de diálogo Escolher produtos de pacote para FriendlyFlixSDK, selecione FriendlyFlix como destino e clique em Adicionar pacote.

Configurar o app iOS para usar o emulador local

  1. Abra FriendlyFlixApp.swift. Você pode pressionar CMD + Shift + O para abrir a caixa de diálogo Abertura rápida e digitar "FriendlyFlixApp" para encontrar o arquivo rapidamente.
  2. Importar o Firebase, o Firebase Auth, o Firebase Data Connect e o SDK gerado para seu esquema
  3. No inicializador, configure o Firebase.
  4. Verifique se o DataConnect e o Firebase Auth estão usando o 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()
  }

  ...

}
  1. Selecione um simulador do iOS no menu suspenso Destino.
  2. Pressione CMD+R ou clique no botão Run no Xcode para executar o app em um simulador.

4. Definir o esquema e pré-preencher o banco de dados

Nesta seção, você vai definir a estrutura e as relações entre as principais entidades do aplicativo de filmes em um esquema. Entidades como Movie, MovieMetaData e outras são mapeadas para tabelas de banco de dados, com relacionamentos estabelecidos usando o Firebase Data Connect e diretivas de esquema GraphQL.

Entidades e relacionamentos principais

O modelo de dados para este app de rastreamento de filmes consiste em várias entidades que você vai criar ao longo deste codelab. Primeiro, você vai criar as entidades principais e, à medida que implementar mais recursos, vai adicionar as entidades necessárias para eles.

Nesta etapa, você vai criar os tipos Movie e MovieMetadata.

Filme

O tipo Movie define a estrutura principal de uma entidade de filme, incluindo campos como title, genre, releaseYear e rating.

No VS Code, adicione a definição do 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

O tipo MovieMetadata estabelece uma relação de um para um com o tipo Movie. Ele inclui outros dados, como o diretor do filme.

Adicione a definição da tabela MovieMetadata ao arquivo dataconnect/schema/schema.gql:

type MovieMetadata @table {
  movie: Movie! @ref
  director: String
}

Campos e padrões gerados automaticamente

O esquema usa expressões como @default(expr: "uuidV4()") para gerar automaticamente IDs e carimbos de data/hora exclusivos. Por exemplo, o campo id no tipo Movie é preenchido automaticamente com um UUID quando um novo registro é criado.

Inserir dados simulados para filmes e metadados de filmes

Com o esquema definido, agora é possível pré-preencher o banco de dados com dados simulados para teste.

  1. No Finder, copie finish/FriendlyFlix/dataconnect/moviedata_insert.gql para a pasta start/FriendlyFlix/dataconnect.
  2. No VS Code, abra dataconnect/moviedata_insert.gql.
  3. Verifique se os emuladores na extensão do Firebase Data Connect estão em execução.
  4. Você vai encontrar um botão Executar (local) na parte de cima do arquivo. Clique aqui para inserir os dados simulados de filmes no banco de dados.
  5. Verifique o terminal Execução do Data Connect para confirmar se os dados foram adicionados corretamente.

Com os dados no lugar, siga para a próxima etapa e saiba como criar consultas no Data Connect.

5. Recuperar e mostrar filmes

Nesta seção, você vai implementar um recurso para mostrar uma lista de filmes.

Primeiro, você vai aprender a criar uma consulta que recupera todos os filmes da tabela movies. O Firebase Data Connect gera código para um SDK type-safe que pode ser usado para executar a consulta e mostrar os filmes recuperados na interface do app.

Definir a consulta ListMovies

As consultas no Firebase Data Connect são escritas em GraphQL, permitindo que você especifique quais campos buscar. No FriendlyFlix, as telas que mostram filmes exigem os seguintes campos: title, description, releaseYear, rating e imageUrl. Além disso, como este é um app SwiftUI, você vai precisar do id para ajudar com a identidade da visualização do SwiftUI.

No VS Code, abra o arquivo dataconnect/connector/queries.gql e adicione a consulta ListMovies:

query ListMovies @auth(level: PUBLIC) {
  movies {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    tags
    description
  }
}

Para testar a nova consulta, clique no botão Executar (local) para executar a consulta no banco de dados local. A lista de filmes do banco de dados vai aparecer na seção Resultados do terminal de execução do Data Connect.

Conectar a consulta ListMovies à tela inicial do app

Agora que você testou a consulta no emulador do Data Connect, é possível chamar a consulta de dentro do app.

Quando você salva queries.gql, o Firebase Data Connect gera o código correspondente à consulta ListMovies no pacote FriendlyFlixSDK.

No Xcode, abra Movie+DataConnect.swift e adicione o seguinte código para mapear de ListMoviesQuery.Data.Movie para 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
  }
}

Abra o arquivo HomeScreen.swift e atualize-o usando o seguinte snippet 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) ?? []
  }

  ...
}

A consulta listMoviesQuery() foi gerada pelo Data Connect quando você salvou queries.gql. Para conferir a implementação em Swift, consulte o arquivo FriendlyFlixOperations.swift no pacote FriendlyFlixSDK.

Executar o app

No Xcode, clique no botão Run para iniciar o app no simulador do iOS.

Quando o app for iniciado, você vai ver uma tela como esta:

Você vai notar que todas as áreas do app (seção principal, principais filmes e lista de exibição) mostram a mesma lista. Isso acontece porque você está usando a mesma consulta para todas essas visualizações. Nas próximas seções, você vai implementar consultas personalizadas.

6. Mostrar o herói e os principais filmes

Nesta etapa, você vai atualizar a forma como os filmes são mostrados na seção principal, que é o carrossel em destaque na parte de cima da tela inicial, e também na seção de filmes mais assistidos abaixo.

No momento, a consulta "ListMovies" recupera todos os filmes. Para otimizar a exibição dessas seções, você vai limitar o número de filmes que cada consulta retorna. A implementação atual da consulta ListMovies ainda não oferece suporte integrado para limitar os resultados. Adicionar suporte para limitar e ordenar é algo que você vai fazer nesta seção.

Melhorar a consulta ListMovies

Abra queries.gql e atualize ListMovies da seguinte maneira para adicionar suporte à ordenação e limitação:

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
  }
}

Isso permite limitar o número de filmes retornados pela consulta e ordenar o conjunto de resultados por classificação e ano de lançamento.

Depois de salvar esse arquivo, o Firebase Data Connect vai gerar novamente o código em FriendlyFlixSDK automaticamente. Na próxima etapa, você vai atualizar o código em HomeScreen.swift para usar esses recursos adicionais.

Usar a consulta aprimorada na interface

Volte para o Xcode e faça as mudanças necessárias em HomeScreen.swift.

Primeiro, atualize heroMoviesRef para buscar os três filmes lançados mais recentemente:

struct HomeScreen {
  ...

  init() {
    heroMoviesRef = connector.listMoviesQuery
      .ref { optionalVars in
        optionalVars.limit = 3
        optionalVars.orderByReleaseYear = .DESC
      }

  }
}

Em seguida, configure outra referência de consulta para os principais filmes e defina o filtro para os cinco filmes mais bem avaliados:

struct HomeScreen {
  ...

  let topMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>

  init() {
    heroMoviesRef = ...

    topMoviesRef = connector.listMoviesQuery
      .ref { optionalVars in
        optionalVars.limit = 5
        optionalVars.orderByRating = .DESC
      }
  }
}

Por fim, atualize a propriedade computada que conecta o resultado dessa consulta à interface:

extension HomeScreen {
  ...

  private var topMovies: [Movie] {
    topMoviesRef.data?.movies.map(Movie.init) ?? []
  }

}

Veja na prática

Execute o app novamente para conferir os três filmes mais recentes na seção principal e os cinco filmes mais bem avaliados na seção "Melhores filmes":

7. Mostrar detalhes de filmes e atores

O usuário agora pode navegar pelos filmes. Ao tocar em um card de filme, alguns detalhes sobre ele são mostrados, mas você pode ter notado que eles não têm muito... detalhe!

Isso porque só buscamos os detalhes necessários para renderizar a seção principal e a seção de melhores filmes: título, uma breve descrição e o URL da imagem.

Na página de detalhes do filme, vamos mostrar mais informações sobre ele. Nesta seção, você vai melhorar o app para que ele possa mostrar os atores do filme e as avaliações na página de detalhes.

Para isso, você precisa fazer algumas coisas:

  • Melhorar o esquema para oferecer suporte a atores e avaliações de filmes
  • Escrever consultas do Firebase Data Connect para buscar detalhes sobre um filme específico
  • Mostrando os resultados na tela de detalhes do filme

Melhorar o esquema

No VS Code, abra dataconnect/schema/schema.gql e adicione as definições de esquema para Actor e 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"
}

Adicionar dados simulados para atores

Com o esquema atualizado, agora é possível preencher o banco de dados com mais dados simulados para teste.

  1. No Finder, copie finish/FriendlyFlix/dataconnect/moviededetails_insert.gql para a pasta start/FriendlyFlix/dataconnect.
  2. No VS Code, abra dataconnect/moviededetails_insert.gql.
  3. Verifique se os emuladores na extensão do Firebase Data Connect estão em execução.
  4. Você vai encontrar um botão Executar (local) na parte de cima do arquivo. Clique aqui para inserir os dados simulados de filmes no banco de dados.
  5. Verifique o terminal de execução do Data Connect para confirmar se os dados foram adicionados corretamente.

Com os dados no lugar, siga para a próxima etapa e defina a consulta para buscar os detalhes do filme.

Definir a consulta GetMovieById

No VS Code, abra o arquivo dataconnect/connector/queries.gql e adicione a 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
    }
  }
}

Conectar a consulta GetMovieById à MovieDetailsView

No Xcode, abra o arquivo MovieDetailsView.swift e atualize a propriedade computada movieDetails para que ela corresponda ao seguinte 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
  }
}

Executar o app

No Xcode, clique no botão Run para iniciar o app no simulador do iOS.

Quando o app for iniciado, toque em um card de filme para mostrar os detalhes. Ele será parecido com o seguinte:

8. Implementar a autenticação do usuário

No momento, o app apresenta informações não personalizadas sobre filmes e atores. Nas etapas a seguir, você vai implementar recursos que associam dados ao usuário conectado. Primeiro, permita que os usuários adicionem filmes à lista de interesses pessoal.

Antes de implementar o recurso de lista de observação, você precisa estabelecer a identidade do usuário. Para isso, você vai integrar o Firebase Authentication, permitindo que os usuários façam login no app.

Talvez você já tenha visto o botão do avatar do usuário no canto superior direito da tela inicial. Ao tocar nessa opção, você vai acessar uma tela em que os usuários podem se inscrever ou fazer login usando e-mail e senha.

Depois que um usuário fizer login, seu app precisará armazenar os detalhes essenciais dele, principalmente o ID de usuário exclusivo e o nome de usuário escolhido.

Ativar o Firebase Authentication

No console do Firebase do seu projeto, acesse a seção "Autenticação" e ative o Firebase Authentication. Em seguida, ative o provedor de autenticação por e-mail/senha.

Na pasta do projeto local, encontre firebase.json e atualize da seguinte maneira para ativar o emulador do Firebase Authentication.

{
  "emulators": {
    "dataconnect": {
    },
    "auth": {
    }
  },
  "dataconnect": {
    "source": "dataconnect"
  }
}

Depois disso, pare e reinicie o emulador do Firebase para que a mudança entre em vigor.

Implementar um gerenciador de autenticação

Na seção a seguir, você vai implementar a lógica que conecta a autenticação de usuários ao seu banco de dados. Isso envolve a criação de um gerenciador de autenticação que detecta logins bem-sucedidos.

Depois que um usuário é autenticado, esse manipulador aciona automaticamente a criação da conta correspondente no banco de dados.

No Xcode, abra o arquivo AuthenticationService.swift e adicione o seguinte 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
  }
}

Esse é um gerenciador de autenticação genérico que permite usar onSignUp para registrar um fechamento que será chamado quando o usuário fizer login.

Dentro desse fechamento, você pode criar uma nova conta de usuário no banco de dados. Mas, antes disso, você precisa criar uma mutação que permita criar ou atualizar novos usuários no banco de dados.

Adicionar uma entidade de usuário ao esquema

O tipo User define uma entidade de usuário. Os usuários podem interagir com filmes deixando avaliações ou marcando como favoritos.

No VS Code, abra o arquivo dataconnect/schema/schema.gql e adicione a seguinte definição de tabela 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)")
}

Definir uma mutação para inserir ou atualizar um usuário

No VS Code, abra o arquivo dataconnect/connector/mutations.gql e adicione a mutação UpsertUser:

mutation UpsertUser($username: String!) @auth(level: USER) {
  user_upsert(
    data: {
      id_expr: "auth.uid"
      username: $username
    }
  )
}

Criar um usuário após fazer login

No Xcode, abra FriendlyFlixApp.swift e adicione o seguinte código ao 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 {
    ...
  }
}

Esse código usa o upsertUserMutation do Firebase Data Connect gerado para você inserir um novo usuário (ou atualizar um usuário existente com o mesmo ID) sempre que um usuário se inscrever com sucesso usando o Firebase Authentication.

Veja na prática

Para verificar se isso funciona, primeiro inscreva-se no app iOS:

  • Se não tiver feito isso, pare e reinicie o emulador do Firebase para garantir que o emulador do Firebase Authentication esteja em execução.
  • No Xcode, clique no botão Run para iniciar o app no simulador do iOS.
  • Clique no ícone do avatar no canto superior direito da tela.
  • Mude para o fluxo de inscrição e inscreva-se no app.

Em seguida, consulte o banco de dados para verificar se o app criou uma nova conta de usuário para o usuário:

  • No VS Code, abra dataconnect/schema/schema.gql e clique em Ler dados na entidade User.
  • Isso vai criar um novo arquivo de consulta chamado User_read.gql.
  • Clique em Executar localmente para ver todos os usuários na tabela de usuários.
  • No painel "Execução da conexão de dados", agora você vai encontrar uma conta do usuário que acabou de se inscrever com

9. Gerenciar filmes favoritos

Nesta seção do codelab, você vai implementar interações do usuário no app de avaliação de filmes, especificamente permitindo que os usuários gerenciem os filmes favoritos. Os filmes marcados como favoritos aparecem na seção "Lista de interesses" do app.

Melhorar o esquema para oferecer suporte aos favoritos

O tipo FavoriteMovie é uma tabela de junção que processa relações de muitos para muitos entre usuários e seus filmes favoritos. Cada tabela vincula um User a um Movie.

Copie e cole o snippet de código no arquivo 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!
}

Definir mutações para adicionar e remover favoritos

Antes que o app possa mostrar os filmes favoritos do usuário, ele precisa indicar quais são os favoritos. Para isso, primeiro adicione duas mutações para marcar um filme como um dos favoritos do usuário ou removê-lo dos favoritos novamente, respectivamente.

  1. No VS Code, abra mutations.gql em dataconnect/connector/mutations.gql.
  2. Adicione as seguintes mutações para processar a ação de adicionar filmes aos favoritos:
## 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 })
}

Conectar as mutações à interface do seu app

Os usuários podem marcar um filme como favorito clicando no ícone de coração na tela de detalhes dele.

Para conectar as mutações que você acabou de criar à interface do app, faça as seguintes mudanças em MovieCardView:

  1. Importar o FriendlyFlixSDK e configurar o 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

  ...
}
  1. Implemente o método toggleFavourite. Ele será chamado sempre que o usuário tocar no ícone de coração no MovieCardView:
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)
      }
    }
  }
}

Isso vai atualizar o estado de favorito do filme atual no banco de dados. Uma última etapa que está faltando é garantir que o estado da UI seja refletido adequadamente.

Definir uma consulta para descobrir se um filme foi marcado como favorito

  1. No VS Code, abra queries.gql em dataconnect/connector.
  2. Adicione a seguinte consulta para verificar se um filme está marcado como favorito:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
    movieId
  }
}
  1. No Xcode, crie uma instância de referência à consulta GetIfFavoritedMovie e implemente a propriedade calculada que determina se o filme mostrado no MovieCardView está marcado como favorito para o usuário atual.
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
  }

  ...

}
  1. Atualize o código em toggleFavourite para executar a consulta sempre que o usuário tocar no botão. Isso garante que a propriedade computada isFavourite sempre retorne o valor correto.
  private func toggleFavourite() {
    Task {
      if isFavourite {
        ...
      }

      let _ = try await isFavouriteRef.execute()
    }
  }

Buscar filmes favoritos

Como etapa final desse recurso, você vai implementar a busca dos filmes favoritos do usuário para que eles possam ser exibidos na lista de exibição.

  1. No VS Code, abra queries.gql em dataconnect/connector/queries.gql e cole a seguinte 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
      }
    }
  }
}

A lista de filmes favoritos do usuário é exibida no LibraryScreen. Essa tela só vai mostrar dados se o usuário estiver conectado. Portanto, primeiro conecte o estado de autenticação da tela ao AuthenticationService do app.

  1. Adicione código para mapear de um FavoriteMovieFavoriteMovies para um Movie para Movie+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
  }
}
  1. No Xcode, abra LibraryScreen e atualize isSignedIn da seguinte maneira:
struct LibraryScreen: View {
  ...

  private var isSignedIn: Bool {
    authenticationService.user != nil
  }

}
  1. Em seguida, importe o Firebase Data Connect e o FriendlyFlixSDK e receba uma referência à 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) ?? []
  }

  ...

}


  1. Verifique se a consulta watchListRef é executada quando a visualização aparece:
extension LibraryScreen: View {
  var body: some View {
    ...
            MovieListSection(namespace: namespace, title: "Watch List", movies: watchList)
              .onAppear {
                Task {
                  try await watchListRef.execute()
                }
  ...

Veja na prática

Agora você pode executar o app e testar o recurso de favoritos que acabou de implementar. Alguns pontos importantes:

  • Verifique se o emulador do Firebase está em execução
  • Verifique se você adicionou dados simulados para os filmes e os detalhes deles.
  • Verifique se você se inscreveu como usuário
  1. No Xcode, clique no botão Run para iniciar o app no simulador do iOS.
  2. Quando o app for iniciado, toque em um card de filme para mostrar os detalhes.
  3. Toque no ícone de coração para marcar o filme como favorito. O coração vai ficar sólido.
  4. Repita isso para alguns filmes.
  5. Acesse a guia "Biblioteca". Agora você vai ver uma lista de todos os filmes marcados como favoritos.

10. Parabéns

Parabéns! Você adicionou o Firebase Data Connect a um app iOS. Agora você conhece as principais etapas necessárias para configurar o Data Connect, criar consultas e mutações e processar a autenticação do usuário.

Opcional: implante na produção

Até agora, este app só usou os emuladores do Firebase. Se quiser saber como implantar esse app em um projeto real do Firebase, continue para a próxima etapa.

11. (Opcional) Implante o app

Até agora, este app foi totalmente local. Todos os dados estão contidos no Pacote de emuladores do Firebase. Nesta seção, você vai aprender a configurar seu projeto do Firebase para que o app funcione em produção.

Ativar o Firebase Authentication

  1. No console do Firebase, acesse a seção Autenticação e clique em Começar.
  2. Acesse a guia Método de login .
  3. Selecione a opção "E-mail/senha" na seção de provedores nativos.
  4. Ative o provedor de e-mail/senha e clique em Salvar.

Ativar o Firebase Data Connect

Importante: se esta for a primeira vez que você implanta um esquema no seu projeto, esse processo vai criar uma instância do Cloud SQL PostgreSQL, o que pode levar cerca de 15 minutos. Não será possível fazer a implantação até que a instância do Cloud SQL esteja pronta e integrada ao Firebase Data Connect.

1. Na interface da extensão do Firebase Data Connect no VS Code, clique em Implantar na produção. 2. Talvez seja necessário analisar as mudanças de esquema e aprovar modificações potencialmente destrutivas. Você vai precisar: - Revisar as mudanças de esquema usando firebase dataconnect:sql:diff - Quando estiver tudo pronto, aplique as mudanças usando o fluxo iniciado por firebase dataconnect:sql:migrate

Sua instância do Cloud SQL para PostgreSQL será atualizada com o esquema e os dados finais implantados. Você pode monitorar o status no console do Firebase.

Agora você pode clicar em "Executar (produção)" no painel "Firebase Data Connect", assim como fez com os emuladores locais, para adicionar dados ao ambiente de produção.

Antes de executar o app iOS novamente, verifique se ele está conectado à instância de produção do projeto:

  1. Abra o menu Produto > Esquema > Editar esquema….
  2. Na seção Executar, desmarque o argumento de inicialização -useEmulator YES.