2019.02.04
まずはログインしているユーザーがつぶやきを投稿できるだけのシンプルなアプリケーションを目指す。Amazon Cognito上ではユーザーは複数作成されるが、つぶやきにはユーザーは関連付けない。
AWS Amplifyで定義したGraphQLスキーマがどのようにAppSyncのスキーマに変換されるのかを学びたい。
現在のamplify/backend/api/amplifysample/schema.graphql
は以下のようになっている。
type Blog @model {
id: ID!
name: String!
posts: [Post] @connection(name: "BlogPosts")
}
type Post @model {
id: ID!
title: String!
blog: Blog @connection(name: "BlogPosts")
comments: [Comment] @connection(name: "PostComments")
}
type Comment @model {
id: ID!
content: String
post: Post @connection(name: "PostComments")
}
ルールに則ってこのファイルに@model
や@connection
をつけていくと、AWS Amplifyの機能であるGraphQL TransformによってGraphQLスキーマに変換されてAppSyncに設定される模様。
今回は既存のスキーマよりもっともっとシンプルにしてみる。
type Post @model {
id: ID!
content: String!
}
つぶやきを表すエンティティとしてPostのみ作成した。これをビルドしてみる。
$ amplify api gql-compile
ビルドした結果、リゾルバーの定義がほとんどなくなった。
$ git add .
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: build/resolvers/Blog.posts.request
deleted: build/resolvers/Blog.posts.response
deleted: build/resolvers/Comment.post.request
deleted: build/resolvers/Comment.post.response
deleted: build/resolvers/Mutation.createBlog.request
deleted: build/resolvers/Mutation.createBlog.response
deleted: build/resolvers/Mutation.createComment.request
deleted: build/resolvers/Mutation.createComment.response
deleted: build/resolvers/Mutation.deleteBlog.request
deleted: build/resolvers/Mutation.deleteBlog.response
deleted: build/resolvers/Mutation.deleteComment.request
deleted: build/resolvers/Mutation.deleteComment.response
deleted: build/resolvers/Mutation.updateBlog.request
deleted: build/resolvers/Mutation.updateBlog.response
deleted: build/resolvers/Mutation.updateComment.request
deleted: build/resolvers/Mutation.updateComment.response
deleted: build/resolvers/Post.blog.request
deleted: build/resolvers/Post.blog.response
deleted: build/resolvers/Post.comments.request
deleted: build/resolvers/Post.comments.response
deleted: build/resolvers/Query.getBlog.request
deleted: build/resolvers/Query.getBlog.response
deleted: build/resolvers/Query.getComment.request
deleted: build/resolvers/Query.getComment.response
deleted: build/resolvers/Query.listBlogs.request
deleted: build/resolvers/Query.listBlogs.response
deleted: build/resolvers/Query.listComments.request
deleted: build/resolvers/Query.listComments.response
modified: build/schema.graphql
modified: cloudformation-template.json
modified: schema.graphql
$ amplify push
# GraphQL関連のコードをアップデートするかどうかを指定
? Do you want to update code for your updated GraphQL API Yes
# GraphQLスキーマに応じたQuery・Mutation・Subscriptionを生成するかどうかを指定
? Do you want to generate GraphQL statements (queries, mutations and subscription) based on your schema types? This wi
ll overwrite your current graphql queries, mutations and subscriptions Yes
CloudFormationが動作してバックエンドの構成を変更してくれる。AppSyncのマネジメントコンソールを見たら、ちゃんとスキーマが変わっていた。
一方、ローカルのプロジェクトで生成されたファイルはamplify/backend/api/amplifysample/src
の中に入っている状態で、既存のsrc/API.ts
は前のままだった。これでは最新のスキーマに合わせてコードを書いていくことができないような...
new file: amplify/backend/api/amplifysample/src/API.ts
new file: amplify/backend/api/amplifysample/src/graphql/mutations.ts
new file: amplify/backend/api/amplifysample/src/graphql/queries.ts
new file: amplify/backend/api/amplifysample/src/graphql/schema.json
new file: amplify/backend/api/amplifysample/src/graphql/subscriptions.ts
念の為もう一度$ amplify push
してみると、今度はsrc/API.ts
等が変更された。
気になって$ amplify status
を実行してみるとプッシュした後にも関わらずAPIがUpdate
になっている...
何か設定を間違えたんだろうか。
本番環境で運用しているときにこういったトラブルが発生したらテンパってしまうかも。今のうちに経験できてよかった。
$ amplify status
| Category | Resource name | Operation | Provider plugin |
| -------- | --------------- | --------- | ----------------- |
| Api | amplifysample | Update | awscloudformation |
| Auth | cognito1b62e7cb | No Change | awscloudformation |
もう一度$ amplify push
してみるも、依然としてUpdate
になっている。AppSyncのスキーマやリゾルバーはちゃんと変更されているようなのでここは無視して先へ進んでみることにした。
HomePageコンポーネントには画面遷移関連の実装が既にあり、サンプルとして見づらくなってしまうのでPostComponentをSharedModuleに定義してそちらに実装してみた。
<ion-list>
<ion-item *ngFor="let post of posts">
<ion-label>{{post.content}}</ion-label>
</ion-item>
<ion-item *ngIf="posts.length === 0">
つぶやきがありません。
</ion-item>
</ion-list>
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button (click)="onAddPostClicked()">
<ion-icon name="add"></ion-icon>
</ion-fab-button>
</ion-fab>
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;
}
}
this.amplifyService.api().graphql()
はAPI.d.ts
の定義によると以下のようになっている。
graphql({ query: paramQuery, variables }: GraphQLOptions): Promise<GraphQLResult> | Observable<object>;
Promise<GraphQLResult> | Observable<object>
を戻り値の型として持つ関数に対してどうやって後続の処理を書いたら良いか分からず、<any>
で型情報を無視してsubscribe
してしまった。
ひとまずこれで、アプリを開いてログインすると以下のような動作をするアプリを作ることができた。
AWS Amplifyを使ってバックエンドを構築するときに若干不具合っぽい動作が見られてしまったが、とりあえずGraphQLで言うところのQuery・Mutation・Subscriptionを試すことができた。
次はaws-amplify-angular
が提供するgraphql
メソッドではなく、AWS AppSync SDKのAWSAppSyncClient
クラスを使ってAppSyncにアクセスするように変更してみたい。