Designing and Engineering "遊び心"駆動開発

Playful IT
2/14 6:14

Apollo Clientもくもく会 2019.2.14@AWSオフィス

はじめに

Apollo Clientを勉強していて、おそらくデータの読み出しと監視を行なっているreadQueryメソッドとwatchQueryメソッドが出てきたので、公式ドキュメントを読んで概要を把握する。

readQueryについてApollo Clientの公式ドキュメントを読んで概要を把握する

Tries to read some data from the store in the shape of the provided GraphQL query without making a network request. This method will start at the root query. To start at a specific id returned by dataIdFromObject use readFragment.

(意訳)ネットワーク通信を行わずに、GraphQLのクエリの形式でストアからデータ取得する。このメソッドはroot queryからスタートする(訳注:現時点では意味不明...)。dataIdFromObjectで返されるIDから始めるには、readFragmentを利用する。

通信せずにキャッシュからデータを読み出すメソッドとのこと。リストのような構造をしているデータを先頭から読み込むイメージ?readFragmentを使うことで位置を指定してデータを読み込めるということ?

後ほど実際に動かしながら検証したい。

watchQueryについてApollo Clientの公式ドキュメントを読んで概要を把握する

watchQuery(options) - Apollo Client

This watches the cache store of the query according to the options specified and returns an ObservableQuery. We can subscribe to this ObservableQuery and receive updated results through a GraphQL observer when the cache store changes.

(意訳)オプションを指定してキャッシュストアを監視しObservableQueryを返す。ObservableQueryを購読することで、キャッシュストアが変更されたときに更新情報を受け取ることができる。

キャッシュストアの変更を監視することができるということは、Optimistic Responseの内容もここで受け取ることができるかもしれない。

Note that this method is not an implementation of GraphQL subscriptions. Rather, it uses Apollo's store in order to reactively deliver updates to your query results.

(意訳)このメソッドはGraphQLのSubscriptionの実装ではないことに注意。むしろ、クエリの結果をリアクティブに伝播させるためにストアにアクセスする。

GraphQLサーバーからプッシュされる情報を購読するものではないとのこと。

For example, suppose you call watchQuery on a GraphQL query that fetches a person's first and last name and this person has a particular object identifer, provided by dataIdFromObject. Later, a different query fetches that same person's first and last name and the first name has now changed. Then, any observers associated with the results of the first query will be updated with a new result object.

(意訳)一意の識別子をもつユーザーの氏名を取得するようなGraphQLのqueryをwatchQueryを呼ぶケースを想定する。後に、他のクエリで同じユーザーの氏名を取得したとして、その時点で取得するユーザーの氏名は変更されているとする。そのとき、最初のクエリ結果を購読しているObserverには新しいオブジェクトが流れてくる。

watchQueryしておけば、変更されたときにUIの各部分がリアクティブに書き変わるということらしい。

Note that if the cache does not change, the subscriber will not be notified.

(意訳)キャッシュが変更されなければ、変更は通知されないことに注意。

基本的なクエリを試す準備をする

Angularアプリケーションを作成する

Angular 7でテスト用のアプリケーションを生成して、Apollo ClientをラップしたAWSAppSyncSDKを使ってreadQuerywatchQueryあたりを試してみる。



$ ng new AngularApolloSample

$ cd AngularApolloSample

# AWS AppSync JavaScript SDKをインストール
$ npm install --save aws-appsync graphql-tag

ディレクトリ構造は以下のようになった。



$ tree src
src
├── app
│   ├── app.component.css
│   ├── app.component.html
│   ├── app.component.spec.ts
│   ├── app.component.ts
│   └── app.module.ts
├── assets
├── environments
│   ├── environment.prod.ts
│   └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
├── test.ts
├── tsconfig.app.json
├── tsconfig.spec.json
└── typings.d.ts

AppSync APIを作成する

AppSyncのマネジメントコンソールから作成。適当にPostモデルを作成する。

Apollo ClientのwatchQuery・readQueryについて調べる

Apollo ClientのwatchQuery・readQueryについて調べる

AngularプロジェクトでAppSyncにつなぐ



ngOnInit() {
  this.client = new AWSAppSyncClient({
    url: 'https://XXXXXXXXXXX.appsync-api.ap-northeast-1.amazonaws.com/graphql',
    region: 'ap-northeast-1',
    auth: {
      type: AUTH_TYPE.API_KEY,
      apiKey: 'XXXXXXXXXXXXX',
    }
  });
}

ボタンを押したらクエリを投げる処理を書く



import { Component, OnInit } from '@angular/core';
import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync';
import { v4 as uuid } from 'uuid';
import * as queries from '../graphql/queries';
import * as mutations from '../graphql/mutations';

interface Post {
  id: string;
  content: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  client;
  content = '';
  posts: Post[] = [];
  posts2: Post[] = [];

  ngOnInit() {
    this.client = new AWSAppSyncClient({
      url: 'https://XXXXXXXXXXXXXXXXXXXXX.appsync-api.ap-northeast-1.amazonaws.com/graphql',
      region: 'ap-northeast-1',
      auth: {
        type: AUTH_TYPE.API_KEY,
        apiKey: 'XXXXXXXXXXXXXXXXXXXXX',
      }
    });

    this.setWatchQuery();
    this.load();
  }

  onCreateClicked() {
    this.client.hydrated().then(client => {
      client.mutate({
        mutation: mutations.createPost,
        variables: {
          input: {
            content: this.content,
          }
        },
        optimisticResponse: () => ({
          createPost: {
            id: uuid(),
            content: this.content,
            __typename: 'Post'
          }
        }),
      }).then(() => {
        this.content = '';
      });
    });
  }

  load() {
    this.client.hydrated().then(client => {
      client.query({
        query: queries.listPosts,
        fetchPolicy: 'network-only',
      }).then(data => {
        this.posts = data.data.listPosts.items;
      });
    });
  }

  setWatchQuery() {
    this.client.hydrated().then(client => {
      client.watchQuery({
        query: queries.listPosts,
        fetchPolicy: 'cache-and-network',
      }).subscribe(data => {
        console.log('subscribe', data);
        this.posts2 = data.data.listPosts.items;
      });
    });
  }
}

今日やったこと

  • readQuery・watchQueryについてのドキュメントを和訳して理解
  • テスト用Angularプロジェクトを作成
  • テスト用AppSync APIを作成
  • AngularアプリからAppSyncに対してMutation・Queryを実行する部分を実装
  • AngularアプリでwatchQueryを利用してみる
  • クエリを発行するときに指定するfetchPolicyで動作が異なることはわかった
  • 若干理解できたreadQuery・watchQueryがChatQLでどう呼ばれているかを見ることができた

課題点

  • fetchPolicyに指定できるタイプによって動作がどう変わるかがわからない。
  • readQuerywatchQueryのユースケースがわからない。

今日学んだこと

  • apollo-link-stateを使うと、Redux等を使って行なっていたクライアントの状態管理をApollo Clientに統合することができる。
  • Apollo Clientの公式Docに詳細な説明が載っていないメソッドはGitHubの関数定義部分を参照すると載っている場合がある。
  • VSCodeの拡張機能を使うとReactのコンポーネントなどがすぐ作れて非常に便利。
関連記事
4/14 11:15

AWS AppSyncでAWSDateTime型を使って日時を扱う

スキーマ定義 日時を扱うためにはAWSDateTime型を利用する。 GraphQLのスキーマでは以下のように使用できる。 リゾルバーで値を自動的にセットする 例えば上のスキーマで、createdAt…

3/3 11:18

AppSyncのリゾルバー(VTL)ケーススタディ

リクエストマッピングテンプレート インデックスを使用してクエリする  ※IAMロールにインデックスへのアクセス権限をつける必要がある。 アンダーバーで始まる列名で検索する  レスポンスマッピングテンプレート ハッシュの配列に属性を追加する  

2018/11/7

GraphQL入門(AWS AppSync)セミナー@AWS Loft 2018/11/6

前書き この記事は2018/11/7のAWS Loftでのセミナー参加中に同時にメモした内容です。内容の誤りが多分にある可能性がありますのでご容赦ください。 資料 https://aws.amazon.com/jp/blogs/news/aws-devday-tokyo-201…

4/13 11:40

AWS AppSyncをGitでバージョン管理する

Serverless FrameworkにAWS AppSync用のプラグインを追加することで、AWS AppSyncのスキーマ・リゾルバーをはじめとした設定が全てコードで書けて、Gitを使ったバージョン管理も行えるようになる。 動作確認 macOS Mojave 10.14.…

2/13 7:03

AWS AppSync Chat Starterのメッセージ表示部分を調査する

前回まで ChatQLでApollo ClientのOptimistic Responseを使っている部分をちょっとだけ変更して、どのような動作をしているかを確認した。 AWS AppSync Chat Starter…

プロフィール