Usar os SDKs do Flutter gerados

Com os SDKs do cliente do Firebase Data Connect, é possível chamar consultas e mutações do lado do servidor diretamente de um app do Firebase. Você gera um SDK do cliente personalizado em paralelo ao projetar os esquemas, as consultas e as mutações que implanta no seu serviço Data Connect. Em seguida, integre os métodos desse SDK à lógica do cliente.

Como já mencionamos, é importante observar que Data Connect consultas e mutações não são enviadas pelo código do cliente e executadas no servidor. Em vez disso, quando implantadas, as operações Data Connect são armazenadas no servidor, como o Cloud Functions. Isso significa que você precisa implantar as mudanças correspondentes do lado do cliente para evitar falhas nos usuários atuais (por exemplo, em versões mais antigas do app).

Por isso, o Data Connect oferece um ambiente de desenvolvimento e ferramentas que permitem prototipar seus esquemas, consultas e mutações implantados no servidor. Ele também gera SDKs do lado do cliente automaticamente enquanto você cria protótipos.

Depois de iterar as atualizações nos apps de serviço e cliente, as atualizações do lado do servidor e do cliente estarão prontas para implantação.

Qual é o fluxo de trabalho de desenvolvimento do cliente?

Se você seguiu os Primeiros passos, conheceu o fluxo geral de desenvolvimento para Data Connect. Neste guia, você encontra informações mais detalhadas sobre como gerar SDKs do Flutter com base no seu esquema e trabalhar com consultas e mutações do cliente.

Resumindo, para usar os SDKs do Flutter gerados nos seus apps cliente, siga estas etapas de pré-requisito:

  1. Adicione o Firebase ao app Flutter.
  2. Instale a CLI do flutterfire dart pub global activate flutterfire_cli.
  3. Execute flutterfire configure.

Depois, siga estas instruções:

  1. Desenvolva o esquema do app.
  2. Configure a geração de SDKs:

  3. Inicialize o código do cliente e importe bibliotecas.

  4. Implemente chamadas paraconsultas e mutações.

  5. Configure e use o emulador Data Connect e faça iterações.

Gerar o SDK do Flutter

Use a CLI Firebase para configurar os SDKs gerados pelo Data Connect nos seus apps. O comando init detecta todos os apps na pasta atual e instala os SDKs gerados automaticamente.

firebase init dataconnect:sdk

Atualizar SDKs durante a criação de protótipos

Se você tiver a extensão Data Connect do VS Code instalada, ela sempre manterá os SDKs gerados atualizados.

Se você não usa a extensão Data Connect do VS Code, pode usar a CLI do Firebase para manter os SDKs gerados atualizados.

firebase dataconnect:sdk:generate --watch

Gerar SDKs em pipelines de build

Use a CLI do Firebase para gerar SDKs Data Connect em processos de build de CI/CD.

firebase dataconnect:sdk:generate

Configurar o código do cliente

Inicializar o app Data Connect

Primeiro, inicialize o app usando as instruções de configuração padrão do Firebase.

Em seguida, instale o plug-in Data Connect:

flutter pub add firebase_data_connect

Inicializar o SDK do Flutter Data Connect

Inicialize sua instância do Data Connect usando as informações que você usou para configurar o Data Connect (tudo disponível na guia Data Connect do console Firebase).

Importar bibliotecas

Há dois conjuntos de importações necessárias para inicializar o código do cliente: importações gerais de Data Connect e importações específicas e geradas do SDK.

// general imports
import 'package:firebase_data_connect/firebase_data_connect.dart';

// generated queries and mutations from SDK
import 'generated/movies.dart';

Usar consultas no lado do cliente

O código gerado já vem com referências de consulta predefinidas. Basta importar e chamar execute neles.

import 'generated/movies.dart';

await MoviesConnector.instance.listMovies().execute();

Chamar métodos de consulta do SDK

Confira um exemplo usando essas funções de atalho de ação:

import 'generated/movies.dart';

function onBtnClick() {
  // This will call the generated Dart from the CLI and then make an HTTP request to the server.
  MoviesConnector.instance.listMovies().execute().the>n(data = showInUI(data)); // == MoviesConnector.instance.listMovies().ref().execute();
}

Campos opcionais

Algumas consultas podem ter campos opcionais. Nesses casos, o SDK do Flutter expõe um método builder, que precisa ser definido separadamente.

Por exemplo, o campo rating é opcional ao chamar createMovie, então você precisa fornecê-lo na função builder.

await MoviesConnector.instance.createMovie({ title: 'Empire Strikes Back', releaseYear: 1980, genre: "Sci-Fi"}).rating(5).execute();

Inscrever-se para receber notificações sobre mudanças

Você pode se inscrever para receber atualizações (que serão enviadas sempre que você executar uma consulta).

QueryRef<ListMoviesData, void> listRef = MoviesConnector.instance.listMovies().ref();

// subscribe will immediately invoke the query if no execute was called on it previously.
listRef.subscribe().listen((data) {
  updateUIWithMovies(data.movies);
});

await MoviesConnector.instance.createMovie({ title: 'Empire Strikes Back', releaseYear: 1980, genre: "Sci-Fi" }).rating(5).execute();
await listRef.execute(); // will update the subscription above`

Processar mudanças em campos de enumeração

O esquema de um app pode conter enumerações, que podem ser acessadas pelas suas consultas GraphQL.

À medida que o design de um app muda, você pode adicionar novos valores compatíveis com enumeração. Por exemplo, imagine que, mais tarde no ciclo de vida do aplicativo, você decida adicionar um valor FULLSCREEN à enumeração AspectRatio.

No fluxo de trabalho do Data Connect, você pode usar ferramentas de desenvolvimento local para atualizar suas consultas e SDKs.

No entanto, antes de lançar uma versão atualizada dos clientes, os clientes implantados mais antigos podem falhar.

Exemplo de implementação resiliente

O SDK gerado força o processamento de valores desconhecidos. Ou seja, o código do cliente precisa desencapsular o objeto EnumValue em Known ou Unknown.

final result = await MoviesConnector.instance.listMovies().execute();

if (result.data != null && result.data!.isNotEmpty) {
  handleEnumValue(result.data![0].aspectratio);
}

void handleEnumValue(EnumValue<AspectRatio> aspectValue) {
  if (aspectValue.value != null) {
    switch(aspectValue.value!) {
      case AspectRatio.ACADEMY:
        print("This movie is in Academy aspect");
        break;
      case AspectRatio.WIDESCREEN:
        print("This movie is in Widescreen aspect");
        break;
      case AspectRatio.ANAMORPHIC:
        print("This movie is in Anamorphic aspect");
        break;
      case AspectRatio.IMAX:
        print("This movie is in IMAX aspect");
    }
  } else {
    print("Unknown aspect ratio detected: ${aspectValue.stringValue}");
  }
}

Ativar o armazenamento em cache no lado do cliente

O Data Connect tem um recurso opcional de cache do lado do cliente, que pode ser ativado editando o arquivo connector.yaml. Quando esse recurso está ativado, os SDKs de cliente gerados armazenam em cache localmente as respostas de consulta, o que pode reduzir o número de solicitações de banco de dados feitas pelo app e permitir que as partes dependentes do banco de dados funcionem quando a disponibilidade da rede é interrompida.

Para ativar o cache do lado do cliente, adicione uma configuração de cache do cliente à configuração do conector:

generate:
  javascriptSdk:
    outputDir: ../dart/
    package: "dataconnect_generated&quot;
    clientCache:
      maxAge: 5s
      storage: memory

Essa configuração tem dois parâmetros opcionais:

  • maxAge: a idade máxima que uma resposta em cache pode ter antes que o SDK do cliente busque valores atualizados. Exemplos: "0", "30s", "1h30m".

    O valor padrão de maxAge é 0, o que significa que as respostas são armazenadas em cache, mas o SDK do cliente sempre vai buscar valores atualizados. Os valores em cache só serão usados quando CACHE_ONLY for especificado como execute() e o resultado inicial retornado de subscribe().

  • storage: o SDK do cliente pode ser configurado para armazenar respostas em cache no armazenamento persistent ou em memory. Os resultados armazenados em cache no armazenamento persistent serão mantidos entre as reinicializações do app. Ao segmentar o Android ou o iOS, o padrão é persistent. Ao segmentar navegadores da Web, apenas o armazenamento memory é compatível.

Depois de atualizar a configuração de cache do conector, gere novamente os SDKs do cliente e reconstrua o app. Depois disso, execute() e subscribe() vão armazenar em cache respostas e usar valores armazenados em cache de acordo com a política configurada. Isso geralmente acontece de forma automática, sem que você precise seguir etapas adicionais. No entanto, observe o seguinte:

  • O comportamento padrão de execute() é o descrito acima: se um resultado for armazenado em cache para uma consulta e o valor armazenado em cache não for mais antigo que maxAge, use o valor armazenado em cache. Esse comportamento padrão é chamado de política de PREFER_CACHE.

    Também é possível especificar invocações individuais de execute() para disponibilizar apenas valores em cache (CACHE_ONLY) ou buscar incondicionalmente valores atualizados do servidor (SERVER_ONLY).

    await queryRef.execute(fetchPolicy: QueryFetchPolicy.cacheOnly);
    
    await queryRef.execute(fetchPolicy: QueryFetchPolicy.serverOnly);
    
  • Quando você chama subscribe(), ele sempre retorna imediatamente o conteúdo em cache, se existir, independente da configuração maxAge. As chamadas subsequentes para execute() vão notificar os listeners de acordo com o maxAge configurado.

Usar mutações no lado do cliente

As mutações são acessíveis da mesma forma que as consultas.

await MoviesConnector.instance.createMovie({ title: 'Empire Strikes Back', releaseYear: 1980, genre: "Sci-Fi" }).rating(5).execute();

Criar protótipos e testar apps do Flutter

Instrumentar clientes para usar um emulador local

É possível usar o emulador Data Connect, seja na extensão do Data Connect para VS Code ou na CLI.

A instrumentação do app para se conectar ao emulador é a mesma nos dois cenários.

import 'package:firebase_data_connect/firebase_data_connect.dart';
import 'generated/movies.dart';

MoviesConnector.instance.dataConnect
          .useDataConnectEmulator('127.0.0.1', 9399);

// Make call<s from your app
Quer>yRefListMoviesData, void ref = MoviesConnector.instance.listMovies.ref();

Para mudar para recursos de produção, adicione um comentário às linhas de conexão com o emulador.

Tipos de dados no SDK do Dart

O servidor Data Connect representa tipos de dados comuns do GraphQL. Elas são representadas no SDK da seguinte maneira.

Tipo Data Connect Dart
Carimbo de data/hora firebase_data_connect.Timestamp
Int (32 bits) int
Data DateTime
UUID string
Int64 int
Ponto flutuante double
Booleano bool
Qualquer firebase_data_connect.AnyValue