こんにちは、tacckです。
シリーズの第二回目です。
前回の記事から引き続き、 Comment Any の開発を進めていきましょう。
今回は、イベント関連の機能を開発します。
イベントの一覧表示、イベントの追加、選択したイベントへ遷移(前回実装分のコメント機能との連携)、イベントの有効化・無効化、といったところですね。
前回までのコードはこちらです。
Amplify で開発してみるシリーズ
* Amplify で開発してみる #1 / API (GraphQL) その1 テーブル一つの実装
* Amplify で開発してみる #2 / API (GraphQL) その2 テーブル連携した実装 (今回)
* Amplify で開発してみる #3 / Authentication と API (GraphQL) を連携した実装
* Amplify で開発してみる #4 / Subscription を使った API (GraphQL) のリアルタイムデータ連携
今回はイベントに関する type
の設定を追加し、このイベントと前回追加したコメントの連携を設定してみましょう。
type Event
@model
{
id: ID!
name: String
active: Boolean!
comments: [Comment] @connection(keyName: "listCommentByEventId", fields: ["id"])
createdAt: AWSDateTime
owner: String
}
type Comment
@model
@key (name: "listCommentByEventId", fields: ["eventId"], queryField: "listCommentByEventId")
{
id: ID!
eventId: ID!
comment: String!
likes: Int!
name: String
updatedAt: AWSDateTime
}
行の色が薄くなっている箇所が、追加した箇所になります。
1~10行目は、イベントの型となります。
項目名 | 型 | 説明 |
---|---|---|
id | ID! | 自身のユニークさを示す情報 |
name | String | イベント名を保持 |
active | Boolean! | イベントの有効・無効を保持 |
comments | [Comment] | このイベント内のコメント(複数)と連携 |
createdAt | AWSDateTime | 作成日時 ( AppSync による自動作成) |
owner | String | 作成したユーザーID (AppSync による自動追加/今回未使用) |
この comments
の後ろにある @connection
ディレクティブと、 type Comment
の方に追加した14行目の @key
ディレクティブが連携の要となります。
@connection
の keyName
フィールドの値 (今回だと listCommentByEventId
) の @key
に対して、 Event
自身の fields
フィールドの値 (今回だと ["id"]
) を使ったクエリを発行し、その結果を comments
として一緒に保持する、という動作をします。
つまり、イベントの検索クエリを実行すれば、そのまま必要なコメントも連携して取得することが可能となります。
一般的な REST API + RDB だと、イベントとコメントを別々の API として呼び出すか、 RDB の SQL の方で JOIN 句を使った API を用意するか、、となります。
データ取得の効率としては後者が必須ですが、 Amplify API (GraphQL) であれば、 JOIN 句の変わりに @connection
と @key
を連携させることで効率よくデータ取得を行なうことができるようになるのです。
より詳しい内容は、オフィシャルのドキュメントを参照してみてください。
API (GraphQL) Directives @connection
ここで、一旦 AWS へ情報をプッシュしておきましょう。
$ amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | ------------- | --------- | ----------------- |
| Api | commentany | Update | awscloudformation |
? Are you sure you want to continue? Yes
The following types do not have '@auth' enabled. Consider using @auth with @model
- Event
- Comment
Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/directives#auth
GraphQL schema compiled successfully.
Edit your schema at /Users/[YOUR_DIRECTORY]/comment-any/amplify/backend/api/commentany/schema.graphql or place .graphql files in a directory at /Users/[YOUR_DIRECTORY]/comment-any/amplify/backend/api/commentany/schema
? Do you want to update code for your updated GraphQL API Yes
? Do you want to generate GraphQL statements (queries, mutations and subscription) based on your schema types?
This will overwrite your current graphql queries, mutations and subscriptions Yes
⠹ Updating resources in the cloud. This may take a few minutes...
(snip)
UPDATE_COMPLETE amplify-commentany-dev-174901 AWS::CloudFormation::Stack Thu Jul 02 2020 17:40:41 GMT+0900 (GMT+09:00)
UPDATE_COMPLETE apicommentany AWS::CloudFormation::Stack Thu Jul 02 2020 17:40:40 GMT+0900 (GMT+09:00)
✔ Generated GraphQL operations successfully and saved at src/graphql
✔ All resources are updated in the cloud
GraphQL endpoint: https://XXXXXXXXXXXXXXXXXXXXXXXXXX.appsync-api.ap-northeast-1.amazonaws.com/graphql
GraphQL API KEY: da2-XXXXXXXXXXXXXXXXXXXXXXXXXX
$
では、イベント機能を実装していきましょう。
実装した内容はこちらのブランチにあるので、つまづいてしまったら確認してみてください。
今回も、必要なライブラリの import
からです。
今回は src/views/Event.vue
の <script>
タグの直下に、下記のように追加してください。
import { API, graphqlOperation } from 'aws-amplify'
import { listEvents } from '@/graphql/queries'
import { createEvent, updateEvent } from '@/graphql/mutations'
created: async function() {
const items = await API.graphql(graphqlOperation(listEvents)).catch(err =>
console.error('listEvents', err),
)
this.events = items.data.listEvents.items
},
2〜4行目で、イベントの一覧を呼び出しています。取得した内容を this.events
へ格納することで、結果を画面に反映することができます。
この辺りは、前回のコメント一覧表示とまったく同じやりかたですね。
こちらでは、 listEvents
のクエリを使ってイベント一覧を取得しています。
addEvent: async function() {
if (!this.newEventName || this.newEventName.length <= 0) {
return
}
const input = {
name: this.newEventName,
active: true,
owner: 'me',
}
const item = await API.graphql(
graphqlOperation(createEvent, { input: input }),
).catch(err => console.error('createEvent', err))
const savedEvent = item.data.createEvent
this.events.push(savedEvent)
this.newEventNameDialog = false
this.newEventName = ''
},
イベント追加ボタンをクリックした後のダイアログに入力されたイベント名を使って、新たにイベントを追加するメソッドとなります。
12〜14行目が GraphQL を使ってイベントを保存しているところです。前回同様、すでに用意されている createEvent
クエリを使うことで、簡単にイベントを保存できています。
activeSwitch: async function(event) {
const index = this.events.findIndex(item => item.id === event.id)
if (index < 0) {
return
}
const item = await API.graphql(
graphqlOperation(updateEvent, { input: event }),
).catch(err => console.error('updateEvent', err))
const savedEvent = item.data.updateEvent
this.events.splice(index, 1, savedEvent)
},
イベントのロック・アンロックボタンをクリックしたときに、呼ばれるメソッドです。
こちらも今まで通り、7〜9行目で更新処理を行なっています。
ちなみに、このメソッド内では状態変更処理がありませんが、 component である src/components/EventItem.vue
の方で処理しているからです。
今回は削除機能は実装しません。
今まで見てきた通り実装はとても簡単にできると思いますので、みなさんで追加機能として実装してみてください。
イベントの一覧が表示できるようになったので、イベントとコメントの連携を実装していきましょう。
具体的には、「イベント一覧から特定のイベントをクリックすると、イベント詳細(コメント一覧)ページへ遷移し、そのイベント内で追加されたコメント一覧が表示される。」ということを実現していきます。
まずは、イベント詳細への遷移から。
<v-row v-for="(event, index) in sortedEvents" :key="index">
<EventItem
:event="event"
:isEventOwner="isEventOwner(event.owner)"
@activeSwitch="activeSwitch"
></EventItem>
</v-row>
これは、イベント一覧で各イベント名を component 化した src/components/EventItem.vue
を使って表示している実装です。
特定のイベントをクリックした場合の処理は、この src/components/EventItem.vue
の中に存在します。
<v-card
:to="{ name: 'EventDetail', params: { eventId: event.id } }"
:outlined="!event.active"
>
このように、 Vuetify のカードを使って表示を整えています。
ここで to
属性を設定することで、クリックされた場合にどこに遷移するか、が決まります。
ここは、 EventDetail
(イベント詳細) ページに eventId
を持って遷移するすることになります。
これで src/views/EventDetail.vue
にうまく遷移するところまできたので、遷移後の処理を追加・修正していきましょう。
import { API, graphqlOperation } from 'aws-amplify'
import { getEvent } from '@/graphql/queries'
import {
createComment,
updateComment,
deleteComment,
} from '@/graphql/mutations'
import
は、上記のように2行目を getEvent
だけにします。 Schema 設定 で説明したように、イベントとそれに連携したコメントを一度に取得できるからです。
実際の使い方が、下のようになります。
created: async function() {
this.linkUrl = location.href
const item = await API.graphql(
graphqlOperation(getEvent, { id: this.eventId }),
).catch(err => console.error('getEvent', err))
this.event = item.data.getEvent
this.comments = this.event.comments.items
},
4〜6行目でイベント取得処理を行なっています。
7行目でイベント情報を格納し、8行目で取得したイベント情報内のコメント一覧を取り出して格納しています。
これだけで、イベントとコメントの連携は実装完了です!
詳細は、こちらを確認してみてください。
また、細かい部分で端折っているところもあるので、うまくできない場合には、下記の実装差分も参考にしてみてください。
特にイベントのロック・アンロック時のボタン制御やコメントの表示などは Vue.js の実装内容となるので、今回の解説ではほとんど触れていません。そういったところのコードも、是非追いかけてみてください。
うまく実装できましたか?
うまくいけば、下記の動画のようにイベントの追加、コメントの連携、イベントのロック、といったものが動作するはずです。
引き続き API (GraphQL) の機能が、とても簡単に扱えるのを見ていきました。
特にイベントとコメントのデータ連携は、思っていた以上に簡単に実現できたと思います。
type
の連携が実装できるようになると、扱えるデータの幅が一気に広がりますし、それに伴ってシステムで実現できるものの幅も広がっていきます。
さらに実現できるものの幅を広げるために、次回は認証機能の導入と API との連携をやってみましょう。