生成されたウェブ SDK を使用する

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

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

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

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

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

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

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

  1. ウェブアプリに Firebase を追加します。

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

  1. アプリのスキーマを開発します。
  2. JavaScript SDKReact ライブラリ、Angular ライブラリを使用して、クライアント コードを初期化します。
  3. React と Angular の場合は、Tanstack Query パッケージをインストールします。
  4. SDK の生成を設定します。

    • Data Connect VS Code 拡張機能の [アプリに SDK を追加] ボタンを使用する
    • JavaScript SDKReactAngularconnector.yaml を更新します。
  5. JavaScript SDKReactAngular を使用して、ライブラリと生成されたコードをインポートします。

  6. JavaScript SDKReactAngular を使用して、クエリとミューテーションの呼び出しを実装します。

  7. JavaScript SDKReactAngular を使用して Data Connect エミュレータを設定し、テストします。

Firebase JavaScript SDK を使用してクライアント コードを実装する

このセクションでは、Firebase JavaScript SDK を使用してクライアントを実装する方法について説明します。

React または Angular を使用している場合は、フレームワーク用の Data Connect SDK の生成に関する代替のセットアップ手順と追加のドキュメントへのリンクをご覧ください。

アプリを初期化する

まず、標準の Firebase シーケンスを使用してアプリを初期化します。

initializeApp({...});

生成された JavaScript SDK をインストールする

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

firebase init dataconnect:sdk

アプリを Data Connect サービスに接続します。

import { connectDataConnectEmulator } from 'firebase/data-connect';
import { connectorConfig } from '@dataconnect/generated';

const dataConnect = getDataConnect(connectorConfig);
// [Optionally] Configure the SDK to use Data Connect local emulator.
connectDataConnectEmulator(dataConnect, 'localhost', 9399);

プロトタイピング中に 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 インポートと、生成された特定の SDK インポートの 2 つのインポート セットが必要です。

一般的なインポートに含まれている ConnectorConfig オブジェクトに注目してください。

// general imports
import { ConnectorConfig, DataConnect, getDataConnect, QueryRef, MutationRef, QueryPromise, MutationPromise } from 'firebase/data-connect';

// generated queries and mutations from SDK
import { listMovies, ListMoviesResponse, createMovie, connectorConfig } from '@dataconnect/generated';

JavaScript SDK からクエリを使用する

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

import { executeQuery } from 'firebase/data-connect';
import { listMoviesRef } from '@dataconnect/generated';

const ref = listMoviesRef();
const { data } = await executeQuery(ref);
console.log(data.movies);

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

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

import { listMovies } from '@dataconnect/generated';
function onBtnClick() {
// This will call the generated JS from the CLI and then make an HTTP request out
// to the server.
  listMovies().then(data => showInUI(data)); // == executeQuery(listMoviesRef);
}

変更を購読する

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

const listRef = listAllMoviesRef();

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

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

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

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

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

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

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

復元力のある実装の例

列挙値に対する switch ステートメントには常に default ブランチを追加し、列挙値と比較する if/else if ブロックには常に else ブランチを追加します。これは JavaScript/TypeScript 言語では強制されませんが、新しい列挙型値が追加された場合にクライアント コードを堅牢にする方法です。

const queryResult = await getOldestMovie();

if (queryResult.data) {
  // we can use a switch statement's "default" case to check for unexpected values
  const oldestMovieAspectRatio = queryResult.data.originalAspectRatio;
  switch (oldestMovieAspectRatio) {
      case AspectRatio.ACADEMY:
      case AspectRatio.WIDESCREEN:
      case AspectRatio.ANAMORPHIC:
        console.log('This movie was filmed in Academy, widescreen or anamorphic aspect ratio!');
        break;
      default:
        // the default case will catch FULLSCREEN, UNAVAILABLE or _UNKNOWN
        // it will also catch unexpected values the SDK isn't aware of, such as CINEMASCOPE
        console.log('This movie was was NOT filmed in Academy, widescreen or anamorphic.');
        break;
  }

  // alternatively, we can check to see if the returned enum value is a known value
  if (!Object.values(AspectRatio).includes(oldestMovieAspectRatio)) {
    console.log(`Unrecognized aspect ratio: ${oldestAspectRatio}`);
  }
} else {
  console.log("no movies found!");
}

JavaScript SDK のミューテーションを使用する

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

import { executeMutation } from 'firebase/data-connect';
import { createMovieRef } from '@dataconnect/generated';

const { data } = await executeMutation(createMovieRef({ movie: 'Empire Strikes Back' }));

Data Connect エミュレータに接続する

必要に応じて、次のように connectDataConnectEmulator を呼び出して Data Connect インスタンスを渡すことで、エミュレータに接続できます。

import { connectDataConnectEmulator } from 'firebase/data-connect';
import { connectorConfig } from '@dataconnect/generated';

const dataConnect = getDataConnect(connectorConfig);
connectDataConnectEmulator(dataConnect, 'localhost', 9399);`

// Make calls from your app

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

React と Angular のクライアント コードを実装する

Firebase Data Connect は、パートナーの Invertase が提供するライブラリ TanStack Query Firebase を使用して、React と Angular のフックを含む生成済み SDK を提供します。

このライブラリは、アプリケーションで Firebase を使用した非同期タスクの処理を大幅に簡素化する一連のフックを提供します。

アプリを初期化する

まず、他の Firebase ウェブアプリと同様に、標準の Firebase シーケンスを使用してアプリを初期化します。

initializeApp({...});

TanStack Query Firebase パッケージをインストールする

プロジェクトに TanStack Query のパッケージをインストールします。

React

npm i --save @tanstack/react-query @tanstack-query-firebase/react
npm i --save firebase@latest # Note: React has a peer dependency on ^11.3.0

Angular

ng add @angular/fire

React または Angular SDK を生成する

前述のとおり、標準のウェブ SDK と同様に、Firebase ツールはスキーマとオペレーションに基づいて SDK の自動生成を処理します。

プロジェクトに React または Angular を追加したばかりの場合は、firebase init dataconnect:sdk を再度実行して、生成された SDK を再構成し、追加のフレームワーク バインディングを含めます。

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

React または Angular クライアント コードを初期化するには、一般的な Data Connect インポート、一般的な TanStack インポート、JS および React 生成 SDK の特定のインポートの 4 つのインポート セットが必要です。

一般的なインポートに ConnectorConfig 型が含まれていることに注意してください。

React

// general imports
import { ConnectorConfig, DataConnect, getDataConnect, QueryRef, MutationRef, QueryPromise, MutationPromise } from 'firebase/data-connect';

// TanStack Query-related functions
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

// generated queries and mutations from SDK
import { ListMoviesResponse, connectorConfig } from '@dataconnect/generated';

// generated React hooks from SDK
import { useListAllMovies, useCreateMovie } from "@dataconnect/generated/react";

Angular

// general imports
import { ConnectorConfig, DataConnect, getDataConnect, QueryRef, MutationRef, QueryPromise, MutationPromise } from 'firebase/data-connect';

// TanStack Query-related functions
import { provideTanStackQuery, QueryClient } from "@tanstack/angular-query-experimental";

// generated queries and mutations from SDK
import { ListMoviesResponse, connectorConfig } from '@dataconnect/generated';

// generated React hooks from SDK
import { injectListAllMovies, injectCreateMovie } from "@dataconnect/generated/angular";

React または Angular クライアントでクエリとミューテーションを使用する

設定が完了したら、生成された SDK のメソッドを組み込むことができます。

次のスニペットでは、生成された SDK の React 用の use 接頭辞付きメソッド useListAllMovies と、Angular 用の inject 接頭辞付きメソッド injectListAllMovies に注目してください。

React

生成された SDK のこのようなオペレーション(クエリとミューテーションの両方)は、TanStackQuery バインディングを呼び出します。

import { useListAllMovies } from '@dataconnect/generated/react';

function MyComponent() {
  const { isLoading, data, error } = useListAllMovies();
  if(isLoading) {
    return <div>Loading...</div>
  }
  if(error) {
    return <div> An Error Occurred: {error} </div>
  }
}

// App.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import MyComponent from './my-component';

function App() {
  const queryClient = new QueryClient();
  return <QueryClientProvider client={queryClient}>
    <MyComponent />
  </QueryClientProvider>
}

Angular

import { injectAllMovies, connectorConfig } from '@dataconnect/generated/angular';
import { provideDataConnect, getDataConnect } from '@angular/fire/data-connect';
import { provideTanStackQuery, QueryClient } from "@tanstack/angular-query-experimental";
const queryClient = new QueryClient();
...
providers: [
  ...
  provideTanStackQuery(queryClient),
  provideDataConnect(() => {
    const dc = getDataConnect(connectorConfig);
    return dc;
  })
]

React と Angular で自動再読み込みクエリを使用する

データが変更されたときに自動的に再読み込みされるようにクエリを構成できます。

React

export class MovieListComponent {
  movies = useListAllMovies();
}

export class AddPostComponent {
  const mutation = useCreateMovie({ invalidate: [listAllMoviesRef()] });
  addMovie() {
    // The following will automatically cause Tanstack to reload its listAllMovies query
    mutation.mutate({ title: 'The Matrix });
  }
}

Angular

// class
export class MovieListComponent {
  movies = injectListAllMovies();
}

// template
@if (movies.isPending()) {
    Loading...
}
@if (movies.error()) {
    An error has occurred: {{  movies.error() }}
}
@if (movies.data(); as data) {
    @for (movie of data.movies; track movie.id) {
    <mat-card appearance="outlined">
        <mat-card-content>{{movie.description}}</mat-card-content>
    </mat-card>
    } @empty {
        <h2>No items!</h2>
    }
}

Data Connect エミュレータに接続する

必要に応じて、次のように connectDataConnectEmulator を呼び出し、生成されたフックに Data Connect インスタンスを渡すことで、エミュレータに接続できます。

React

import { getDataConnect, connectDataConnectEmulator } from 'firebase/data-connect';
import { connectorConfig } from '@dataconnect/generated';
import { useListAllMovies } from '@dataconnect/generated/react';

const dc = getDataConnect(connectorConfig);
connectDataConnectEmulator(dc, 'localhost', 9399);

class AppComponent() {
  ...
  const { isLoading, data, error } = useListAllMovies(dc);
  ...
}

Angular

// app.config.ts
import { provideDataConnect } from '@angular/fire/data-connect';
import { getDataConnect, connectDataConnectEmulator } from 'firebase/data-connect';
provideDataConnect(() => {
  const dc = getDataConnect(connectorConfig);
  connectDataConnectEmulator(dc, 'localhost', 9399);
  return dc;
}),

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

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

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

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

generate:
  javascriptSdk:
    outputDir: ../web/
    package: "@dataconnect/generated"
    clientCache:
      maxAge: 5s
      storage: memory

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

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

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

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

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

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

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

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

SDK のデータ型

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

Data Connect TypeScript
タイムスタンプ 文字列
日付 文字列
UUID 文字列
Int64 文字列
Double 数値
浮動小数点数 数値

プロトタイピング中に 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