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

Playful IT
2/4 10:59

AWS AmplifyのAPI.graphqlではなくAWSAppSyncClientでAppSyncにアクセスしてみる

AWS Amplifyが提供するGraphQL

AWS Amplifyを使ってAppSyncを利用する場合、import { AmplifyService } from 'aws-amplify-angular';で読み込んだAmplifyServiceをDIして以下のようにQuery・Mutation・Subscriptionを利用することができる。



// Query
this.amplifyService.api().graphql(graphqlOperation(queries.listPosts))

// Mutation
this.amplifyService.api().graphql(graphqlOperation(mutations.createPost, { input: {
  content: `つぶやきテスト ${new Date()}`,
}}));

// Subscription
this.amplifyService.api().graphql(graphqlOperation(subscriptions.onCreatePost))

一方、AppSyncの強みである、オフラインでのアプリの利用とオンラインに復帰したときの同期を使うためにはAppSync SDKを利用する必要がある。

AppSync SDKをインストールする



$ npm install --save aws-appsync graphql-tag

AppSync SDKを使った版に書き換える



import { Component, OnInit } from '@angular/core';
import { AmplifyService } from 'aws-amplify-angular';
import { graphqlOperation } from 'aws-amplify';
import * as queries from '../../../../graphql/queries';
import * as mutations from '../../../../graphql/mutations';
import * as subscriptions from '../../../../graphql/subscriptions';

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

  posts = [];

  constructor(
    private amplifyService: AmplifyService,
  ) { }

  ngOnInit() {
    // サーバーからプッシュされる情報を受け取る
    (<any>this.amplifyService.api().graphql(graphqlOperation(subscriptions.onCreatePost))).subscribe(data => {
      this.posts.push(data.value.data.onCreatePost);
    });

    // 初回のデータ読み込みを行う
    this.loadData();
  }

  async onAddPostClicked() {
    this.amplifyService.api().graphql(graphqlOperation(mutations.createPost, { input: {
      content: `つぶやきテスト ${new Date()}`,
    }}));
  }

  private async loadData() {
    const ret = await this.amplifyService.api().graphql(graphqlOperation(queries.listPosts));
    this.posts = (<any>ret).data.listPosts.items;
  }
}



import { Component, OnInit } from '@angular/core';
import { AmplifyService } from 'aws-amplify-angular';
import gql from 'graphql-tag';
import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync';
import * as queries from '../../../../graphql/queries';
import * as mutations from '../../../../graphql/mutations';
import * as subscriptions from '../../../../graphql/subscriptions';
import amplify from '../../../../aws-exports';

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

  client;
  posts = [];

  constructor(
    private amplifyService: AmplifyService,
  ) { }

  async ngOnInit() {
    this.client = new AWSAppSyncClient({
      url: amplify.aws_appsync_graphqlEndpoint,
      region: amplify.aws_appsync_region,
      auth: {
        type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
        jwtToken: async () => (await this.amplifyService.auth().currentSession()).getIdToken().getJwtToken(),
      }
    });

    this.client.subscribe({ query: gql(subscriptions.onCreatePost) }).subscribe(data => {
      this.posts.push(data.data.onCreatePost);
    }, error => {
      console.warn(error);
    });

    // 初回のデータ読み込みを行う
    this.loadData();
  }

  async onAddPostClicked() {
    this.client.mutate({
      mutation: gql(mutations.createPost),
      variables: {
        input: {
          content: `つぶやきテスト ${new Date()}`,
        }
      },
    });
  }

  private async loadData() {
    this.client.query({
      query: gql(queries.listPosts),
    }).then(data => {
      this.posts = data.data.listPosts.items;
    });
  }
}

AWSAppSyncClientクラスのインスタンスはアプリケーション全体で一つで問題なさそうなので、CoreModuleにAppSyncServiceのようなサービスを作ってそこで持たせておくのが良いかもしれない。

AWSAppSyncClientクラスのインスタンス化部分の解説



this.client = new AWSAppSyncClient({
  url: amplify.aws_appsync_graphqlEndpoint,
  region: amplify.aws_appsync_region,
  auth: {
    type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
    jwtToken: async () => (await this.amplifyService.auth().currentSession()).getIdToken().getJwtToken(),
  }
});

urlには、AWS Amplifyが生成するaws-exports.jsaws_appsync_graphqlEndpointの内容を指定する。 regionには、AWS Amplifyが生成するaws-exports.jsaws_appsync_regionの内容を指定する。

また、AppSyncの認証モードをAMAZON_COGNITO_USER_POOLSにした場合は必ずjwtTokenが必要になる。

認証モードがAMAZON_COGNITO_USER_POOLSの場合は、ログインしていないユーザーはどのQuery・Mutation・Subscriptionも利用できない。未ログインユーザーに対してAPIの利用を許可するには、そもそもAppSyncの認証モードをIAMにする必要がある。

では、AMAZONCOGNITOUSER_POOLSモードはなんのためにあるのか?という疑問が湧いてくるが、このモードはサクッとアプリケーションのAPIを構築するときに使うものだそう。

ユーザーのアクセス制限も、Amazon Cognitoのユーザーグループに応じてQuery・Mutation・Subscriptionを許可・拒否するくらいしかできない。

細かいアクセス制御をしたい場合はAppSyncの認証モードをIAMにする。

関連記事
2/5 6:44

サーバーレスを学ぶのにAWS Amplifyを使うのをやめた件

AWS Amplifyとの出会い 目黒にあるAWS Loft Tokyoにて行われたBlack Beltセミナーの公開収録に参加して初めてAmplifyを知った。 AWS BlackBeltセミナー Amplify@AWS Loft 2018/11/6 それまでAWS…

2/4 7:32

AWS AmplifyでAppSyncのGraphQLスキーマを作成する

目指すもの まずはログインしているユーザーがつぶやきを投稿できるだけのシンプルなアプリケーションを目指す。Amazon Cognito上ではユーザーは複数作成されるが、つぶやきにはユーザーは関連付けない。 学びたいこと AWS Amplifyで定義したGraphQL…

2/4 6:52

AWS Amplifyのログイン状態に応じてIonic 4の画面を切り替える

前回まで Ionic 4のアプリケーションを作成して、AWS Amplifyを使ってバックエンドを構築した。ログイン周りのビューはAWS Amplifyで提供される <amplify-authenticator> コンポーネントを利用して構築した。 Angular…

2/2 11:08

AWS AmplifyをIonic 4で使うときのモジュール分割を考える

前回まで AWS AmplifyをIonic 4で使ってみる Ionic 4(Angular 7)のアプリケーションを作成して、AWS AmplifyでAWS上にAWS AppSyncとAmazon Cognitoを使ったAPI…

2/1 9:52

AWS AmplifyをIonic 4で使ってみる

あらまし AWSのマネージドサービスをうまく活用することで、高い可用性を持ったアプリケーションを開発できる。2019年はスマホアプリ・PWAのバックエンドにAWS…

プロフィール