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

2019.02.04

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にする。