こんにちは、tacckです。
既報のとおり、社内の座席管理システム「せきとりくん」というものを作り、無事にリリースしました。🎉
こちらは AWS Amplify を使って作成しています。
API (GraphQL) の機能を活用できると手軽に Serverless なシステムを作れるようになるので、大変良いですね。
そんなわけで、今回の記事を含め全四回(予定)をかけて API (GraphQL) を実際に使った開発の流れを見ていきたいと思います。
Amplify で開発してみるシリーズ
* Amplify で開発してみる #1 / API (GraphQL) その1 テーブル一つの実装 (今回)
* Amplify で開発してみる #2 / API (GraphQL) その2 テーブル連携した実装
* Amplify で開発してみる #3 / Authentication と API (GraphQL) を連携した実装
* Amplify で開発してみる #4 / Subscription を使った API (GraphQL) のリアルタイムデータ連携
このシリーズでは、ミーティングやLTなど複数の人が集まった時に、コメントを気軽に投稿できるシステムを作っていきます。
現在は、リモートでの働く割合も増えてきていると思いますが、リモートのミーティングで誰でも気軽に意見を言える、後から見直すこともできる、といった活用もできるのではないかと思います。
アプリケーション名は、"Do you have any comment?" (コメントはありますか?) をもじって、
Comment Any としておきます。
おおよそ、下記の機能を備えたシステムとして開発を進めたいと思います。
とはいえ、今回は Amplify にフォーカスしたいので、システムのUIについては私が Vue.js でモックを作成済みです。
GitHub tacck/comment-any baseブランチ
今回は、これをベースに「コメント」に関する機能を実装していきましょう。
ソースコードは、私の方で作成したモックをベースに話を進めていきます。
Node.js と Yarn は下記のバージョンで進めていきます。
$ node -v
v12.4.0
$ yarn -v
1.21.1
ソースコードを GitHub から clone して、開発の準備を進めていきましょう。
$ git clone https://github.com/tacck/comment-any.git
$ cd comment-any
$ git checkout -b base origin/base
$ yarn install
まず、この状態で動作確認してみます。 yarn serve
後に、 http://localhost:8080
へアクセスしてみてください。
下記のような画面となれば OK です。
では、 Amplify の設定に入っていきましょう。
まずは、初期設定です。
$ amplify init
Scanning for plugins...
Plugin scan successful
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project commentany
? Enter a name for the environment dev
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using vue
? Source Directory Path: src
? Distribution Directory Path: dist
? Build Command: yarn build
? Start Command: yarn serve
Using default provider awscloudformation
For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html
? Do you want to use an AWS profile? Yes
? Please choose the profile you want to use default
Adding backend environment dev to AWS Amplify Console app: XXXXXXXXXXXXXX
⠧ Initializing project in the cloud...
(snip)
CREATE_COMPLETE amplify-commentany-dev-XXXXXX AWS::CloudFormation::Stack Thu Jun 25 2020 17:49:51 GMT+0900 (GMT+09:00)
CREATE_COMPLETE DeploymentBucket AWS::S3::Bucket Thu Jun 25 2020 17:49:48 GMT+0900 (GMT+09:00)
✔ Successfully created initial AWS cloud resources for deployments.
✔ Initialized provider successfully.
Initialized your environment successfully.
Your project has been successfully initialized and connected to the cloud!
Some next steps:
"amplify status" will show you what you've added already and if it's locally configured or deployed
"amplify add <category>" will allow you to add features like user login or a backend API
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify console" to open the Amplify Console and view your project status
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
Pro tip:
Try "amplify add api" to create a backend API and then "amplify publish" to deploy everything
$
前回と同様、行の色が薄くなっている箇所が、入力の必要なところになります。基本的に書かれてある通りに進めてしまって問題ありません。
(詳しくわかる方は、自由にカスタマイズしてみてください。)
Amplify Framework と、 Vue.js 用のパッケージを追加します。
$ yarn add aws-amplify @aws-amplify/ui-vue
追加したら、下記のように src/main.js
ファイルを更新します。
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify'
import Amplify from 'aws-amplify'
import '@aws-amplify/ui-vue'
import aws_exports from './aws-exports'
Amplify.configure(aws_exports)
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
render: h => h(App),
}).$mount('#app')
Amplify API (GraphQL) 機能を、プロジェクトに追加します。
$ amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: commentany
? Choose the default authorization type for the API API key
? Enter a description for the API key:
? After how many days from now the API key should expire (1-365): 365
? Do you want to configure advanced settings for the GraphQL API No, I am done.
? Do you have an annotated GraphQL schema? No
? Do you want a guided schema creation? Yes
? What best describes your project: Single object with fields (e.g., “Todo” with ID, name, description)
? Do you want to edit the schema now? No
The following types do not have '@auth' enabled. Consider using @auth with @model
- Todo
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
Successfully added resource commentany locally
Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
$
色々と入力を促されますが、記載を参考に進めていけば問題ありません。
実際にデータを保存する形式を GraphQL の Schema として定義します。
type
が、いわゆる RDB のテーブルと同じような意味合いになります。
type Comment @model {
id: ID!
eventId: ID!
comment: String!
likes: Int!
name: String
updatedAt: AWSDateTime
}
type 内の各項目は、それぞれ下記のような意味合いとなります。
項目名 | 型 | 説明 |
---|---|---|
id | ID! | 自身のユニークさを示す情報 |
eventId | ID! | (後々) イベントとの連携を示す情報 |
comment | String! | コメント内容を保持 |
likes | Int! | Like 数を保持 |
name | String | 投稿したユーザー名を保持 (システム内では未使用) |
updatedAt | AWSDateTime | 更新日時 ( AppSync による自動更新) |
より詳しい内容は、オフィシャルのドキュメントを参照してみてください。
ここまでできたら、一旦 AWS へ情報をプッシュしておきましょう。
$ amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | ------------- | --------- | ----------------- |
| Api | commentany | Create | awscloudformation |
? Are you sure you want to continue? Yes
The following types do not have '@auth' enabled. Consider using @auth with @model
- 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 generate code for your newly created GraphQL API Yes
? Choose the code generation language target javascript
? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js
? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
⠏ Updating resources in the cloud. This may take a few minutes...
(snip)
UPDATE_COMPLETE amplify-commentany-dev-XXXXXX AWS::CloudFormation::Stack Thu Jun 25 2020 18:07:58 GMT+0900 (GMT+09:00)
UPDATE_COMPLETE_CLEANUP_IN_PROGRESS amplify-commentany-dev-XXXXXX AWS::CloudFormation::Stack Thu Jun 25 2020 18:07:58 GMT+0900 (GMT+09:00)
CREATE_COMPLETE apicommentany AWS::CloudFormation::Stack Thu Jun 25 2020 18:07:55 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/EventDetail.vue
の <script>
タグの直下に、下記のように追加してください。
import { API, graphqlOperation } from 'aws-amplify'
import { listComments } from '@/graphql/queries'
import {
createComment,
updateComment,
deleteComment,
} from '@/graphql/mutations'
created: async function() {
this.linkUrl = location.href
const items = await API.graphql(graphqlOperation(listComments)).catch(err =>
console.error('listComments', err),
)
this.comments = items.data.listComments.items
},
4〜6行目で、コメント一覧を呼び出しています。取得した内容を this.comments
へ格納することで、結果を画面に反映することができます。
( created
内に実装)
listComments
が GrqphQL のクエリとなっています。詳しい内容は、 src/graphql/queries.js
にあります。 (先ほどの amplify push
時に生成されたものです。)
export const listComments = /* GraphQL */ `
query ListComments(
$filter: ModelCommentFilterInput
$limit: Int
$nextToken: String
) {
listComments(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
eventId
comment
likes
name
updatedAt
createdAt
}
nextToken
}
}
`;
こういった基本的なクエリも Amplify が自動生成してくれるので、かなり簡単に GraphQL を利用することができます。
addComment: async function(inputComment) {
if (!inputComment || inputComment.length <= 0) {
return
}
const comment = {
eventId: this.event.id,
name: this.loginUserName,
comment: inputComment,
likes: 0,
}
const item = await API.graphql(
graphqlOperation(createComment, { input: comment }),
).catch(err => console.error('createComment', err))
const savedComment = item.data.createComment
this.comments.push(savedComment)
this.scrollToId(savedComment.id)
this.pushUpdatedIds(savedComment.id)
},
このメソッドが、コメントの投稿ボタンをクリックした時に呼ばれます。引数の inputComment
に、投稿するコメントが入ってくる感じですね。
13〜15行目が GraphQL を使ってコメントを保存しているところです。ここも、すでに定義済みの createComment
クエリを使うことで、簡単に保存処理が実装できています。
また、ここで保存した結果の savedComment
を使うことで、 id
がきちんと生成された状態になります。
addLike: async function(elementId) {
const comment = this.getComment(elementId)
if (comment === null) {
return
}
const beforeIndex = this.getCommentIndex(elementId)
const input = {
id: comment.id,
likes: comment.likes + 1,
}
const item = await API.graphql(
graphqlOperation(updateComment, { input: input }),
).catch(err => console.error('updateComment', err))
const savedComment = item.data.updateComment
comment.likes = savedComment.likes
comment.updatedAt = savedComment.updatedAt
const afterIndex = this.getCommentIndex(elementId)
if (beforeIndex > afterIndex) {
this.scrollToId(comment.id)
this.pushUpdatedIds(comment.id)
}
},
ここは Like ( likes
) を 1 増やしてコメントを更新しています。
追加などと同じように、14〜16行目だけで更新処理が実装できています。
更新後の情報が savedComment
で返ってくるので、その内容を表示に反映させます。
deleteComment: async function(elementId) {
const index = this.comments.findIndex(item => item.id === elementId)
if (index < 0) {
return
}
const comment = this.getComment(elementId)
const input = {
id: comment.id,
}
await API.graphql(
graphqlOperation(deleteComment, { input: input }),
).catch(err => console.error('deleteComment', err))
this.comments.splice(index, 1)
},
ここは、コメントの削除ボタンがクリックされた場合に呼ばれます。
ここでも、定義済みの GraphQL クエリである deleteComment
を使って削除処理を実行しています。(12〜14行目)
各機能のコードの詳細は、こちらを確認してみてください。
どうにもうまくできない場合は、下記の実装差分を見て対応の漏れが無いかも見てください。
うまく実装できれば、画面上でコメントの追加・削除・ Like での並び替え、が動作します。
API (GraphQL) の機能を、とても簡単に組み込むことができました。
基本的な GraphQL のクエリは Amplify が自動生成してくれるので、まずは細かいことを気にせずにすぐに使い始めることができるようになります。
「ちょっとデータを読み書きしたいけど、 RDB を立てるほどでもないしなぁ。」という方、是非 Amplify を試してみてください。
次回は、イベントの type
を追加し、今回作成したコメントと連携を取れるようにしてみたいと思います。