PostgresでGraphQLサブスクリプションを使用してリアルタイムアプリを構築する方法
公開: 2022-03-10この記事では、リアルタイムアプリケーションの構築に伴う課題と、新しいツールが推論しやすいエレガントなソリューションでそれらにどのように対処しているかを見ていきます。 これを行うには、Postgres、GraphQL、Reactを使用し、バックエンドコードを使用せずに、リアルタイムのポーリングアプリ(リアルタイムの全体的な統計を使用したTwitterのポーリングなど)を構築します。
主な焦点は、バックエンドのセットアップ(すぐに使用できるツールのデプロイ、スキーマモデリング)、およびフロントエンドのUI / UXではなくGraphQLとのフロントエンド統合の側面です(ReactJSの知識があれば役立ちます)。 チュートリアルセクションでは、数値によるペイントアプローチを採用しているため、アプリ全体を最初から作成するのではなく、スキーマモデリングとUIのGitHubリポジトリのクローンを作成して微調整します。
All Things GraphQL
GraphQLについて知っておくべきことをすべて知っていますか? 疑問がある場合は、Eric Baerが、その起源、欠点、および操作方法の基本についての詳細なガイドを提供します。 関連記事を読む→
この記事を読み続ける前に、次のテクノロジー(または代替)の実用的な知識が有益であることを述べておきます。
- ReactJS
これは、クライアントライブラリのドキュメントに従うことで、任意のフロントエンドフレームワーク、AndroidまたはIOSに置き換えることができます。 - Postgres
他のデータベースを使用することもできますが、さまざまなツールを使用して、この投稿で概説されている原則が引き続き適用されます。
このチュートリアルコンテキストを他のリアルタイムアプリに非常に簡単に適合させることもできます。
下部にある付随するGraphQLペイロードに示されているように、実装する必要のある3つの主要な機能があります。
- 投票の質問とオプションのリスト(左上)を取得します。
- ユーザーが特定の投票質問に投票できるようにします(「投票」ボタン)。
- 投票の結果をリアルタイムで取得し、棒グラフで表示します(右上。このユースケースの正確なレプリカであるため、現在オンラインのユーザーのリストを取得する機能を詳しく説明できます)。
リアルタイムアプリの構築に関する課題
リアルタイムアプリの構築(特にフロントエンド開発者または最近フルスタック開発者になるための移行を行った人として)は、解決するのが難しいエンジニアリングの問題です。 これは一般的に、現代のリアルタイムアプリがどのように機能するかです(サンプルアプリのコンテキストで):
- フロントエンドは、いくつかの情報でデータベースを更新します。 ユーザーの投票はバックエンドに送信されます。つまり、投票/オプションとユーザー情報(
user_id
、option_id
)です。 - 最初の更新は、投票データを集約する別のサービスをトリガーして、リアルタイムでアプリに中継される出力をレンダリングします(誰かが新しい投票を行うたびに、これが効率的に行われると、更新された投票のデータのみが処理され、この投票にサブスクライブしているクライアントのみが更新されます):
- 投票データは、最初に、
poll_results
サービスをトリガーするregister_vote
サービス(ここで何らかの検証が行われると想定)によって処理されます。 - リアルタイムで集計されたポーリングデータは、
poll_results
サービスによってフロントエンドに中継され、全体的な統計が表示されます。
- 投票データは、最初に、
このモデルは、従来のAPI構築アプローチから派生しているため、同様の問題があります。
- 一連の手順のいずれかがうまくいかず、UXがハングしたままになり、他の独立した操作に影響を与える可能性があります。
- APIレイヤーは、複数のサービスとやり取りするフロントエンドアプリの単一の窓口であるため、多くの労力が必要です。 また、WebSocketベースのリアルタイムAPIを実装する必要があります。これには普遍的な標準がないため、ツールの自動化のサポートは限られています。
- フロントエンドアプリは、リアルタイムAPIを使用するために必要な配管を追加する必要があります。また、リアルタイムアプリで通常見られるデータ整合性の問題を解決する必要がある場合もあります(選択した例ではそれほど重要ではありませんが、実際のメッセージの順序付けでは重要です) -タイムチャットアプリ)。
- 多くの実装では、リアルタイムAPIのサポートを容易にするために、サーバー側で追加の非リレーショナルデータベース(Firebaseなど)を使用しています。
GraphQLと関連するツールがこれらの課題にどのように対処するかを見てみましょう。
GraphQLとは何ですか?
GraphQLは、APIのクエリ言語の仕様であり、クエリを実行するためのサーバー側ランタイムです。 この仕様は、アプリ開発を加速し、標準化されたデータベースに依存しないデータアクセス形式を提供するためにFacebookによって開発されました。 仕様に準拠したGraphQLサーバーは、以下をサポートする必要があります。
- 読み取りのクエリ
データソース(データベース、REST API、または別のGraphQLスキーマ/サーバーの1つまたは組み合わせのいずれか)からネストされたデータを要求するための要求タイプ。 - 書き込みのミューテーション
前述のデータソースにデータを書き込んだり中継したりするためのリクエストタイプ。 - ライブクエリのサブスクリプション
クライアントがリアルタイム更新をサブスクライブするための要求タイプ。
GraphQLも型付きスキーマを使用します。 エコシステムには、開発/コンパイル時にエラーを特定するのに役立つツールがたくさんあり、実行時のバグが少なくなります。
GraphQLがリアルタイムアプリに最適な理由は次のとおりです。
- ライブクエリ(サブスクリプション)は、GraphQL仕様の暗黙的な部分です。 GraphQLシステムには、ネイティブのリアルタイムAPI機能が必要です。
- リアルタイムクエリの標準仕様は、クライアント側ツールに関するコミュニティの取り組みを統合し、GraphQLAPIと統合する非常に直感的な方法をもたらしました。
GraphQLと、データベースイベント用のオープンソースツールとサーバーレス/クラウド機能の組み合わせは、非同期のビジネスロジックと、構築と管理が容易なリアルタイム機能を備えたクラウドネイティブアプリケーションを構築するための優れた基盤を提供します。 この新しいパラダイムは、優れたユーザーエクスペリエンスと開発者エクスペリエンスももたらします。
この記事の残りの部分では、オープンソースツールを使用して、このアーキテクチャ図に基づいてアプリを構築します。
リアルタイムの投票/投票アプリの構築
GraphQLの概要を説明した後、最初のセクションで説明したポーリングアプリの構築に戻りましょう。
3つの機能(または強調表示されたストーリー)は、アプリが作成するさまざまなGraphQLリクエストタイプを示すために選択されています。
- クエリ
投票の質問とそのオプションを取得します。 - 突然変異
ユーザーに投票させます。 - サブスクリプション
投票結果のリアルタイムダッシュボードを表示します。
前提条件
- Herokuアカウント(無料枠を使用、クレジットカードは不要)
GraphQLバックエンド(以下の次のポイントを参照)とPostgresインスタンスをデプロイします。 - Hasura GraphQLエンジン(無料、オープンソース) Postgresですぐに使用できるGraphQLサーバー。
- Apolloクライアント(無料のオープンソースSDK)
クライアントアプリをGraphQLサーバーと簡単に統合します。 - npm (無料のオープンソースパッケージマネージャー)
Reactアプリを実行します。
データベースとGraphQLバックエンドのデプロイ
PostgresとGraphQLEngineのそれぞれのインスタンスをHerokuの無料利用枠にデプロイします。 気の利いたHerokuボタンを使用して、シングルクリックでこれを行うことができます。
注:このリンクをたどるか、Heroku(または他のプラットフォーム)用のドキュメントHasuraGraphQLデプロイメントを検索することもできます。
追加の設定は必要ありません。「アプリのデプロイ」ボタンをクリックするだけです。 デプロイが完了したら、アプリのURLをメモします。
<app-name>.herokuapp.com
たとえば、上のスクリーンショットでは、次のようになります。
hge-realtime-app-tutorial.herokuapp.com
これまでに行ったことは、Postgresのインスタンス(Herokuの用語ではアドオンとして)と、このPostgresインスタンスを使用するように構成されたGraphQLEngineのインスタンスをデプロイすることです。 その結果、すぐに使用できるGraphQL APIができましたが、データベースにテーブルやデータがないため、これはまだ役に立ちません。 それでは、すぐにこれに対処しましょう。
データベーススキーマのモデリング
次のスキーマ図は、投票アプリの単純なリレーショナルデータベーススキーマを示しています。
ご覧のとおり、スキーマは、外部キー制約を利用する単純な正規化されたスキーマです。 GraphQLエンジンによって1:1または1:多の関係として解釈されるのはこれらの制約です(たとえば、 poll:options
は1:多の関係です。これは、各ポーリングには、外部キー制約によってリンクされる複数のオプションがあるためです。 poll
テーブルのid
列とoption
テーブルのpoll_id
列)。 関連データはグラフとしてモデル化できるため、GraphQLAPIを強化できます。 これはまさにGraphQLエンジンが行うことです。
上記に基づいて、スキーマをモデル化するために次のテーブルと制約を作成する必要があります。
-
Poll
世論調査の質問をキャプチャするためのテーブル。 -
Option
各投票のオプション。 -
Vote
ユーザーの投票を記録します。 - 次のフィールド間の外部キー制約(
table : column
):-
option : poll_id → poll : id
-
vote : poll_id → poll : id
-
vote : created_by_user_id → user : id
-
スキーマ設計ができたので、Postgresデータベースに実装しましょう。 このスキーマを即座に起動するために、次のことを行います。
- GraphQL EngineCLIをダウンロードします。
- このリポジトリのクローンを作成します。
$ git clone clone https://github.com/hasura/graphql-engine $ cd graphql-engine/community/examples/realtime-poll
-
hasura/
に移動し、config.yaml
を編集します。endpoint: https://<app-name>.herokuapp.com
- (クローン作成によってダウンロードした)プロジェクトディレクトリ内から、CLIを使用して移行を適用します。
$ hasura migrate apply
バックエンドについては以上です。 これで、GraphQL Engineコンソールを開いて、すべてのテーブルが存在することを確認できます(コンソールはhttps://<app-name>.herokuapp.com/console
で入手できます)。
注:コンソールを使用して、個々のテーブルを作成し、UIを使用して制約を追加することにより、スキーマを実装することもできます。 GraphQL Engineでの移行の組み込みサポートの使用は、必要なテーブルを表示し、関係/制約を構成するための移行がサンプルリポジトリに含まれているため、利用可能だった便利なオプションです(これは、趣味を構築しているかどうかに関係なく、強くお勧めしますプロジェクトまたは本番環境に対応したアプリ)。
フロントエンドReactアプリとGraphQLバックエンドの統合
このチュートリアルのフロントエンドは、投票の質問、投票するオプション、および集計された投票結果を1か所に表示するシンプルなアプリです。 先に述べたように、最初にこのアプリの実行に焦点を当て、最近デプロイされたGraphQL APIをすぐに使用できるようにします。この記事の前半で見たGraphQLの概念が、このようなアプリのさまざまなユースケースにどのように役立つかをご覧ください。 、次に、GraphQL統合が内部でどのように機能するかを調べます。
注: ReactJSを初めて使用する場合は、これらの記事のいくつかを確認することをお勧めします。 アプリのReact部分の詳細については説明しませんが、代わりに、アプリのGraphQLの側面に焦点を当てます。 Reactアプリの構築方法の詳細については、リポジトリのソースコードを参照してください。
フロントエンドアプリの構成
- 前のセクションでクローン化されたリポジトリで、 src / apollo.jsファイル(
/community/examples/realtime-poll
フォルダー内)のHASURA_GRAPHQL_ENGINE_HOSTNAME
を編集し、上からHerokuアプリのURLに設定します。export const HASURA_GRAPHQL_ENGINE_HOSTNAME = 'random-string-123.herokuapp.com';
- リポジトリ/アプリフォルダのルート(
/realtime-poll/
)に移動し、npmを使用して前提条件のモジュールをインストールしてから、アプリを実行します。$ npm install $ npm start
これで、アプリをいじることができるはずです。 先に進んで、何度でも投票すると、結果がリアルタイムで変化することに気付くでしょう。 実際、このUIの別のインスタンスを設定し、それを同じバックエンドにポイントすると、すべてのインスタンスにわたって集計された結果を確認できます。
では、このアプリはGraphQLをどのように使用しますか? 読む。
舞台裏:GraphQL
このセクションでは、アプリを強化するGraphQL機能について説明し、次のセクションでの統合のしやすさのデモンストレーションを行います。
投票コンポーネントと集計結果グラフ
左上の投票コンポーネントは、すべてのオプションを含む投票を取得し、データベース内のユーザーの投票をキャプチャします。 これらの操作は両方とも、GraphQLAPIを使用して実行されます。 投票の詳細を取得するために、クエリを作成します(GraphQLの紹介からこれを覚えていますか?):
query { poll { id question options { id text } } }
react-apollo
のMutationコンポーネントを使用して、フォームが送信されたときに変数optionId
とuserId
を使用してミューテーションが実行されるように、ミューテーションをHTMLフォームに接続できます。
mutation vote($optionId: uuid!, $userId: uuid!) { insert_vote(objects: [{option_id: $optionId, created_by_user_id: $userId}]) { returning { id } } }
投票結果を表示するには、投票テーブルのデータからオプションごとの投票数を導出する必要があります。 Postgresビューを作成し、GraphQLエンジンを使用して追跡し、この派生データをGraphQLで利用できるようにすることができます。
CREATE VIEW poll_results AS SELECT poll.id AS poll_id, o.option_id, count(*) AS votes FROM (( SELECT vote.option_id, option.poll_id, option.text FROM ( vote LEFT JOIN public.option ON ((option.id = vote.option_id)))) o LEFT JOIN poll ON ((poll.id = o.poll_id))) GROUP BY poll.question, o.option_id, poll.id;
poll_results
ビューは、 vote
テーブルとpoll
テーブルのデータを結合して、各オプションごとの投票数の集計数を提供します。
このビュー、react-google-charts、およびreact-apollo
のサブスクリプションコンポーネントでGraphQLサブスクリプションを使用すると、任意のクライアントから新しい投票が発生したときにリアルタイムで更新されるリアクティブチャートを接続できます。
subscription getResult($pollId: uuid!) { poll_results(where: {poll_id: {_eq: $pollId}}) { option { id text } votes } }
GraphQLAPI統合
前述したように、オープンソースのSDKであるApollo Clientを使用して、ReactJSアプリをGraphQLバックエンドと統合しました。 Apolloクライアントは、Pythonのリクエスト、JavaScriptの標準httpモジュールなどのHTTPクライアントライブラリに類似しています。 HTTPリクエスト(この場合はPOSTリクエスト)の作成の詳細をカプセル化します。 構成( src/apollo.js
で指定)を使用して、クエリ/ミューテーション/サブスクリプション要求( src / GraphQL.jsxで指定され、REACTアプリのJavaScriptコードで動的に置換できる変数を使用するオプションがあります)を実行します。 GraphQLエンドポイント。 また、GraphQLエンドポイントの背後にある型付きスキーマを活用して、前述のリクエストのコンパイル/開発時の検証を提供します。 クライアントアプリがGraphQLAPIに対してライブクエリ(サブスクリプション)リクエストを行うのがいかに簡単かを見てみましょう。
SDKの構成
Apollo Client SDKはGraphQLサーバーを指す必要があるため、このような統合に通常必要な定型コードを自動的に処理できます。 したがって、これは、フロントエンドアプリのセットアップ時にsrc /apollo.jsを変更したときに行ったこととまったく同じです。
GraphQLサブスクリプションリクエストの作成(Live-Query)
前のセクションで見たサブスクリプションをsrc / GraphQL.jsxファイルで定義します。
const SUBSCRIPTION_RESULT = ` subscription getResult($pollId: uuid!) { poll_results ( order_by: option_id_desc, where: { poll_id: {_eq: $pollId} } ) { option_id option { id text } votes } }`;
この定義を使用して、Reactコンポーネントを接続します。
export const Result = (pollId) => ( <Subscription subscription={gql`${SUBSCRIPTION_RESULT}`} variables={pollId}> {({ loading, error, data }) => { if (loading) return
読み込んでいます... </ p>; if(エラー)return
エラー:</ p>; 戻る ( <div> <div> {renderChart(data)} </ div> </ div> ); }} </サブスクリプション> )。
ここで注意すべきことの1つは、上記のサブスクリプションもクエリである可能性があるということです。 あるキーワードを別のキーワードに置き換えるだけで「ライブクエリ」が得られ、Apollo ClientSDKがこのリアルタイムAPIをアプリにフックするのに必要なのはそれだけです。 ライブクエリから新しいデータセットが存在するたびに、SDKはこの更新されたデータを使用してグラフの再レンダリングをトリガーします( renderChart(data)
呼び出しを使用)。 それでおしまい。 本当に簡単です!
最終的な考え
3つの簡単なステップ(GraphQLバックエンドの作成、アプリスキーマのモデリング、フロントエンドとGraphQL APIの統合)で、セットアップなどの不要な詳細に煩わされることなく、完全に機能するリアルタイムアプリをすばやく接続できます。 WebSocket接続。 その通り、GraphQLのような抽象化を支援するコミュニティツールの力があります。
これがおもしろくて、次のサイドプロジェクトまたは本番アプリのためにGraphQLをさらに調査したい場合は、GraphQLツールチェーンを構築するために使用できるいくつかの要素を次に示します。
- パフォーマンスとスケーラビリティ
GraphQLは、フロントエンドアプリによって直接消費されることを目的としています(バックエンドのORMに勝るものはありません。実際の生産性のメリットは、これを行うことで得られます)。 したがって、ツールはデータベース接続を効率的に使用するためのスマートである必要があり、簡単に拡張できる必要があります。 - 安全
以上のことから、データへのアクセスを許可するには、成熟した役割ベースのアクセス制御システムが必要です。 - オートメーション
GraphQLエコシステムを初めて使用する場合、GraphQLスキーマを手書きしてGraphQLサーバーを実装することは困難な作業のように思えるかもしれません。 ツールの自動化を最大化して、ユーザー中心のフロントエンド機能の構築などの重要な作業に集中できるようにします。 - 建築上記の取り組みは些細なことのように思えますが、本番環境グレードのアプリのバックエンドアーキテクチャには、スキーマスティッチングなどの高度なGraphQLの概念が含まれる場合があります。さらに、リアルタイムAPIを簡単に生成/使用できるため、非同期でリアクティブなビルドの可能性が広がります。復元力があり、本質的にスケーラブルなアプリ。 したがって、GraphQLツールがアーキテクチャを合理化する方法を評価することが重要です。
関連リソース
- ここでアプリのライブバージョンをチェックできます。
- 完全なソースコードはGitHubで入手できます。
- データベーススキーマを調べてGraphQLクエリのテストを実行したい場合は、ここで実行できます。