生成された Flutter SDK を使用する

Firebase Data Connect クライアント SDK を使用すると、Firebase アプリからサーバーサイドのクエリとミューテーションを直接呼び出すことができます。Data Connect サービスにデプロイするスキーマ、クエリ、ミューテーションを設計するのと並行して、カスタム クライアント SDK を生成します。次に、この SDK のメソッドをクライアント ロジックに統合します。

別の場所でも説明したように、Data Connect クエリとミューテーションはクライアント コードによって送信され、サーバーで実行されるわけではないことに注意してください。代わりに、デプロイ時に Data Connect オペレーションは Cloud Functions などのサーバーに保存されます。つまり、既存のユーザー(古いバージョンのアプリなど)を壊さないように、対応するクライアントサイドの変更をデプロイする必要があります。

そのため、Data Connect には、サーバーにデプロイされたスキーマ、クエリ、ミューテーションのプロトタイプを作成できるデベロッパー環境とツールが用意されています。また、プロトタイピング中にクライアントサイド SDK を自動的に生成します。

サービスアプリとクライアント アプリの更新を繰り返し行うと、サーバーサイドとクライアント サイドの両方の更新をデプロイできるようになります。

クライアント開発のワークフローとは何ですか?

スタートガイドに沿って、Data Connect の開発フロー全体について説明しました。このガイドでは、スキーマから Flutter SDK を生成し、クライアント クエリとミューテーションを操作する方法について詳しく説明します。

まとめると、生成された Flutter SDK をクライアント アプリで使用するには、次の前提条件の手順を行います。

  1. Flutter アプリに Firebase を追加します。
  2. flutterfire CLI dart pub global activate flutterfire_cli をインストールします。
  3. flutterfire configure を実行します。

次に、以下のリソースをご覧ください。

  1. アプリのスキーマを開発します。
  2. SDK の生成を設定します。

  3. クライアント コードを初期化してライブラリをインポートします

  4. クエリの呼び出しミューテーションを実装します。

  5. Data Connect エミュレータを設定して使用し、反復処理を行います。

Flutter SDK を生成する

Firebase CLI を使用して、アプリで Data Connect 生成 SDK を設定します。init コマンドは、現在のフォルダ内のすべてのアプリを検出し、生成された SDK を自動的にインストールします。

firebase init dataconnect:sdk

プロトタイピング中に SDK を更新する

Data Connect VS Code 拡張機能がインストールされている場合、生成された SDK は常に最新の状態に保たれます。

Data Connect VS Code 拡張機能を使用しない場合は、Firebase CLI を使用して生成された SDK を最新の状態に保つことができます。

firebase dataconnect:sdk:generate --watch

ビルド パイプラインで SDK を生成する

Firebase CLI を使用して、CI/CD ビルドプロセスで Data Connect SDK を生成できます。

firebase dataconnect:sdk:generate

クライアント コードを設定する

Data Connect アプリを初期化する

まず、Firebase の標準設定手順に沿ってアプリを初期化します。

次に、Data Connect プラグインをインストールします。

flutter pub add firebase_data_connect

Data Connect Flutter SDK を初期化する

Data Connect の設定に使用した情報(Firebase コンソールの [Data Connect] タブで確認可能)を使用して、Data Connect インスタンスを初期化します。

ライブラリをインポートする

クライアント コードを初期化するには、一般的な Data Connect インポートと、生成された特定の SDK インポートの 2 つのインポート セットが必要です。

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

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

クライアントサイドでクエリを使用する

生成されたコードには、事前定義されたクエリ参照がすでに含まれています。必要なのは、それらをインポートして execute を呼び出すことだけです。

import 'generated/movies.dart';

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

SDK のクエリ メソッドを呼び出す

これらのアクション ショートカット関数を使用した例を次に示します。

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().then(data => showInUI(data)); // == MoviesConnector.instance.listMovies().ref().execute();
}

任意のフィールド

一部のクエリには省略可能なフィールドがあります。このような場合、Flutter SDK はビルダー メソッドを公開するため、個別に設定する必要があります。

たとえば、rating フィールドは createMovie を呼び出すときに省略可能であるため、ビルダー関数で指定する必要があります。

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

変更を購読する

変更をサブスクライブできます(クエリを実行するたびに更新されます)。

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`

列挙型フィールドの変更を処理する

アプリのスキーマには列挙型を含めることができ、GraphQL クエリでアクセスできます。

アプリの設計が変更されたら、サポートされている新しい列挙値を追加できます。たとえば、アプリケーションのライフサイクルの後半で、AspectRatio 列挙型に FULLSCREEN 値を追加するとします。

Data Connect ワークフローでは、ローカル開発ツールを使用してクエリと SDK を更新できます。

ただし、クライアントの更新バージョンをリリースする前に、以前にデプロイされたクライアントが破損する可能性があります。

復元力のある実装の例

生成された SDK では、不明な値の処理が強制されます。つまり、クライアント コードは EnumValue オブジェクトを Known または 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}");
  }
}

クライアントサイド キャッシュを有効にする

Data Connect には、オプションのクライアントサイド キャッシュ機能があります。この機能は、connector.yaml ファイルを編集することで有効にできます。この機能を有効にすると、生成されたクライアント SDK はクエリ レスポンスをローカルにキャッシュに保存します。これにより、アプリが作成するデータベース リクエストの数を減らし、ネットワークの可用性が中断されたときにアプリのデータベース依存部分が動作するようにできます。

クライアントサイド キャッシュ保存を有効にするには、コネクタ構成にクライアント キャッシュ保存構成を追加します。

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

この構成には 2 つのパラメータがあり、どちらも省略可能です。

  • maxAge: クライアント SDK が新しい値を取得する前に、キャッシュに保存されたレスポンスが保持できる最大期間。例: 「0」、「30s」、「1h30m」。

    maxAge のデフォルト値は 0 です。これは、レスポンスがキャッシュに保存されるものの、クライアント SDK は常に新しい値を取得することを意味します。キャッシュに保存された値は、CACHE_ONLYexecute() に指定され、subscribe() から返された初期結果が使用される場合にのみ使用されます。

  • storage: クライアント SDK は、persistent ストレージまたは memory のいずれかにレスポンスをキャッシュに保存するように構成できます。persistent ストレージにキャッシュ保存された結果は、アプリの再起動後も保持されます。Android または iOS をターゲットとする場合、デフォルトは persistent です。ウェブブラウザをターゲットとする場合、memory ストレージのみがサポートされます。

コネクタのキャッシュ保存構成を更新したら、クライアント SDK を再生成してアプリを再ビルドします。これにより、execute()subscribe() は、構成したポリシーに従ってレスポンスをキャッシュに保存し、キャッシュに保存された値を使用します。通常、この処理は自動的に行われるため、追加の操作は不要です。ただし、次の点にご注意ください。

  • execute() のデフォルトの動作は上記のとおりです。クエリの結果がキャッシュに保存され、キャッシュに保存された値が maxAge より古くない場合は、キャッシュに保存された値を使用します。このデフォルトの動作は PREFER_CACHE ポリシーと呼ばれます。

    また、execute() の個々の呼び出しで、キャッシュに保存された値のみを処理する(CACHE_ONLY)か、サーバーから新しい値を無条件で取得する(SERVER_ONLY)かを指定することもできます。

    await queryRef.execute(fetchPolicy: QueryFetchPolicy.cacheOnly);
    
    await queryRef.execute(fetchPolicy: QueryFetchPolicy.serverOnly);
    
  • subscribe() を呼び出すと、maxAge の設定に関係なく、キャッシュに保存されたコンテンツが存在する場合は常にすぐに返されます。execute() の後続の呼び出しでは、構成された maxAge に従ってリスナーに通知します。

クライアントサイドでミューテーションを使用する

ミューテーションはクエリと同じ方法でアクセスできます。

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

Flutter アプリのプロトタイプを作成してテストする

ローカル エミュレータを使用するようにクライアントを計測する

Data Connect エミュレータは、Data Connect VS Code 拡張機能または CLI から使用できます。

エミュレータに接続するためのアプリの計測は、どちらのシナリオでも同じです。

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

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

// Make calls from your app
QueryRef<ListMoviesData, void> ref = MoviesConnector.instance.listMovies.ref();

本番環境リソースに切り替えるには、エミュレータへの接続に関する行をコメントアウトします。

Dart SDK のデータ型

Data Connect サーバーは、一般的な GraphQL データ型を表します。これらは SDK で次のように表されます。

Data Connect Dart
タイムスタンプ firebase_data_connect.Timestamp
Int(32 ビット) int
日付 DateTime
UUID 文字列
Int64 int
浮動小数点数 double
ブール値 ブール値
すべて firebase_data_connect.AnyValue