AWS AppSyncでGraphQL【実践編その1(Vue+Amplify+Cognito)】

Pocket
LINEで送る

aws-sns

お疲れさまです!フクロウラボ若杉です。

5月も、もう終わりですね。この調子で行くと2019年もあっという間な気がしています。。という前回と全く同じ書き出しなのがヤバイな〜。

さて、前回は、AWSのAppSyncのシミュレーターから、GraphQLの操作についてちょっと触れていましたが、今回は実際に簡単なアプリを作って見たいと思います。

ざっくり概要を述べると、フロントエンドのvue.jsから直接GraphQLを操作することを考えています。

簡単なメモアプリを作ってみたいと思います。

構成としては、

  • Vue.js(フロントエンドの実装)
  • AWS Amplify(JavaScriptライブラリ&AWS系構築のツールチェーン)
  • AWS Cognito(ユーザー認証)
  • AWS AppSync + DynamoDB(API)

※カッコの部分は主な役割

という感じの構成で作っていこうと思っています。

スクリーンショット 2019-05-24 10.58.12

AWS Black Belt Online Seminar AWS Amplify より引用

 

Amplifyとは

今回はAmplify(アンプリファイ)というAWSが提供しているツールが重要な役割を果たしていますので、Amplifyについて少し説明したいと思います。

スクリーンショット 2019-05-23 12.48.11

AWS Black Belt Online Seminar AWS Amplify より引用

基本的にはAWS CLI(Command Line Interface)や言語毎に提供されているSDKなどと同様にAWSの各種サービスの操作を行う事ができるツールです。

ただ、AWS CLIやSDKは、サーバサイドで実行されることを想定されていますが、Amplifyはフロントエンドで実行されることを想定されています。そういったところの特徴として、コマンド1つで複数のAWSのサービスを立ち上げるツールチェーンやjavascriptライブラリを内包している点などが挙げられます。またオープンソースなため、独自の拡張を施すこともできます。

※もう少し深いところまで知りたい方は、こちらから動画をご覧ください。

 

Vue.jsの準備

Vue-CLIのインストール

npm install -g @vue/cli

Vueプロジェクトの作成

プロジェクトディレクトリを作成する任意のディレクトリへ移動

vue create memo-app

Vueプロジェクトの設定は、下記で行いました。

Vue CLI v3.7.0
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Router, Vuex, CSS Pre-processors, Linter
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with node-sass)
? Pick a linter / formatter config: TSLint
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In package.json
? Save this as a preset for future projects? No

しばらくすると、プロジェクトが完成します。

htmlのテンプレートでpugを使うので、プロジェクトディレクトリに移動して、下記を実行。

vue add pug

pugについては、こちらを参考に。

ざっくり、

<div class="hoge">
 <ul>
 <li>item 1</li>
 <li>item 2</li>
 </ul>
</div>

div.hoge
 ul
  li item 1
  li item 2

という感じで、記述できるようになります。

 

Amplifyの準備

Amplifyのインストール

npm install -g @aws-amplify/cli

Amplifyの初期設定(ユーザー作成)

amplify configure

これを実行するとブラウザ立ち上がり、AWSのログイン画面になります。

スクリーンショット 2019-05-23 15.28.53

ブラウザでログインを行い、ターミナルへ戻ります。下記の状態になっているので表示通りenterキーを押します。

Follow these steps to set up access to your AWS account:

Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue

するとIAMのユーザーを作成するための設定を対話形式で行っていく形になります。

途中またブラウザに戻りAWSのIAMのコンソールでユーザー作成する画面に遷移します。そこで、画面にそってユーザーを作成します。最終的に発行したユーザーのaccessKeyIdとsecretAccessKeyを対話型コマンドラインに入力します。

Enter the access key of the newly created user:
? accessKeyId: **************
? secretAccessKey: **************
...
Successfully set up the new user.

これで、Amplifyを使う際のアカウント設定が完了します。

次にプロジェクトでAmplifyを使うための設定を行います。

Vueプロジェクトに移動して、下記を実行します。

amplify init

すると、また対話ベースのやり取りが始まりまりますので、今回は下記のように進めました。

Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project memo-app
? Enter a name for the environment demo
? Choose your default editor: Vim (via Terminal, Mac OS only)
? 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 amplify
⠏ Initializing project in the cloud...
.
.
.

これでAmplifyの下準備は完了しました。

 

Vueプラグインのインストール

Vueのライブラリをインストールします。今回は、Element UIとAWS Amplify、@types/nodeをインストールします。

プロジェクトディレクトリに移動して、下記を実行。

npm i --save-dev element-ui aws-amplify @types/node

もろもろインストールが完了したら、Vueの下準備は完了です。

 

Amplifyの文法

ここからは、フロントエンド側を離れて、クラウド側の設定を行っていきたいと思います。

主に、

  • Cognitoの設定
  • AppSyncの設定

の2つを行っていきたいのですが、その前にAmplify CLIについて少し共有したいと思います。

Amplify CLIでは主に下記の8つのカテゴリの操作を行えます。

  1. Analytics(ユーザのセッション属性などを測定)
  2. API(REST/GraphQL APIの利用)
  3. Authentication(認証APIとpre-build UI componentの利用)
  4. Interactions(DeepLeaningを利用したBotの構築)
  5. PubSub(IoTなどのリアルタイムなデータのやり取り)
  6. Push Notifications(キャンペーンや分析機能をもったプッシュ通知)
  7. Storage(静的コンテンツのシンプルな管理)
  8. XR(AR/VRコンテンツの組み込み)

※2019/05/23現在

※詳細は、こちらを参照。

それぞれの機能を追加・構築したい場合は、

amplify xxxx add

とコマンドを実行すると対話型のUIが始まりますので、そこで設定を進めていきます。

ただ、その対話が完了した後に、環境が整っているわけではなく、この状態ではローカルにCloudFormationのテンプレートデータが作成されている状態で、

amplify xxxx push

 

というコマンドを実行することで初めてクラウド環境が構築されていきます。

こういったフローがあるのが、フロントエンドなローカルで実行すること想定されていてAWS CLIと違う点ですね。

 

ユーザー認証用Cognitoの構築

今回作成するメモアプリでは、ログインをしてからメモを残すというアプリ考えていますので、当然ユーザー認証の機能が必要です。

そういったユーザー認証機能もAmplifyでサクッと作れるようになっているのですが、そこで使われているのがAWS Cognitoというサービスです。

Cognitoには、主に3つの機能が存在するのですが、詳しくはこちらを参考にしてもらえればと思います。

その中のCongnitoのユーザープールという機能を使って、アプリにユーザー認証機能を実装します。

Cognito側でユーザーの情報を格納するデータベース的な役割も吸収してくれます。

scenario-authentication-cup

Amazon Cognito ユーザープール より引用

また、上記の図にあるように、Google、facebook、amazonなどのSocialサインインにも対応していて、自前でOAuthの実装も必要なくCognitoで吸収してくれています。

では、実際にAmplifyでCognitoのユーザープールを構築してみましょう。

amplify auth add

対話型UIが始まるので、下記のようにデフォルト設定でemailのみで作成しました。

Using service: Cognito, provided by: awscloudformation
 
 The current configured provider is Amazon Cognito. 
 
 Do you want to use the default authentication and security configuration? Default configuration
 Warning: you will not be able to edit these selections. 
 How do you want users to be able to sign in when using your Cognito User Pool? Email
 Warning: you will not be able to edit these selections. 
 What attributes are required for signing up? (Press <space> to select, <a> to toggle all, <i> to invert selection)Email

お作法に則って、pushすることで、クラウドへ反映されます。

amplify auth push

 

API(GraphQL)用のAppSyncとDynamoDBの構築

次にAPI(GraphQL)の実装を行いたいと思います。AppSyncについては、前回の記事を参考にしてみてください。

AWS AppSyncでGraphQL【入門編】

amplify api add

下記の感じで設定しました。

? Please select from one of the below mentioned services GraphQL
? Provide API name: memoapp
? Choose an authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project
? 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

pushしてクラウドへデプロイします。

amplify api push

1行もコードを書いていませんが、一応、ここまででクラウド側の構築・実装は全て完了しています。

 

フロントエンドの実装

viewテンプレートも全て記載すると長くなってしまうので、テンプレート以外の主なファイルは下記。

main.ts

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import ElementUI from "element-ui";
import "../node_modules/element-ui/lib/theme-chalk/index.css";
import Amplify from "aws-amplify";
import appSyncConfig from "./aws-exports";

Amplify.configure(appSyncConfig);

Vue.config.productionTip = false;
Vue.use(ElementUI);

new Vue({
 router,
 store,
 render: (h) => h(App),
}).$mount("#app");

tsconfig.json

{
 "compilerOptions": {
  "noImplicitAny": false,
  "target": "esnext",
  "module": "esnext",
  "strict": true,
  "jsx": "preserve",
  "importHelpers": true,
  "moduleResolution": "node",
  "experimentalDecorators": true,
  "esModuleInterop": true,
  "allowSyntheticDefaultImports": true,
  "sourceMap": true,
  "baseUrl": ".",
  "types": [
   "webpack-env",
   "node"
  ],
  "paths": {
   "@/*": [
    "src/*"
   ]
  },
  "lib": [
   "esnext",
   "dom",
   "dom.iterable",
   "scripthost"
  ]
 },
 "include": [
  "src/**/*.ts",
  "src/**/*.tsx",
  "src/**/*.vue",
  "tests/**/*.ts",
  "tests/**/*.tsx"
 ],
 "exclude": [
  "node_modules"
 ]
}

src/App.vue

<template lang="pug">
 #app
 router-view
</template>

<style lang="scss">
body {
 background-color: #2c3e50;
 margin: 0;
}

#app {
 font-family: 'Avenir', Helvetica, Arial, sans-serif;
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
 text-align: center;
 color: #ffffff;
}

.title {
 font-size: 4rem;
 margin-top: 10vh
}
</style>

router.ts

import Vue from "vue";
import Router from "vue-router";
import SignIn from "./views/SignIn.vue";
import SignUp from "./views/SignUp.vue";
import Memo from "./views/Memo.vue";

Vue.use(Router);

export default new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/",
      name: "Memo",
      component: Memo,
    },
    {
      path: "/signIn",
      name: "signIn",
      component: SignIn,
    },
    {
      path: "/signUp",
      name: "signUp",
      component: SignUp,
    },
  ],
});

 

動作確認

まず、メールアドレスとパスワードを入力して、自分のアカウントを作成します。

※ちなみに、Cognitoでバリデーション処理もされていて、エラーなケースはちゃんとエラーメッセージを受け取っているのですが、表示部分を端折っています。。

スクリーンショット 2019-05-24 2.01.50

こちらもCognitoから認証用のメールが送信されます。

スクリーンショット 2019-05-24 10.45.34

メールの受信ボックスに下記のようなメールが送信されているので、上記の画面で78399と入力します。

スクリーンショット 2019-05-24 10.45.56

すると、ブラウザの通知で完了の旨が表示されます。

スクリーンショット 2019-05-24 10.46.50

一旦、ログイン画面へ戻されるので、先程、登録したアカウントでログインします。

スクリーンショット 2019-05-24 10.47.11

すると、下記のようなフォームが表示され、ここからメモを作成する感じです。

スクリーンショット 2019-05-24 10.47.46

↓ メモ追加

スクリーンショット 2019-05-24 10.50.28

ちゃんとAppSyncのGraphQLからメモリストを取得できているようです。

スクリーンショット 2019-05-24 14.10.59

一応、AWSコンソールも確認します。

DynamoDBにもitemが入っていますね。

スクリーンショット 2019-05-24 14.12.40

ユーザーアカウントもいくつか作成してみましたが、問題なくCognitoで管理されているようです。

スクリーンショット 2019-05-24 14.14.12

動作確認は以上になります。

まとめ

今回、AWS Amplifyを初めて使ったのですが、突然ブラウザが起動するやpushして初めて反映されるところなど、CLIとしてちょっと変わった動きだったので、最初は何をやっているのかよくわかりませんでした。しかし、挙動になれてくると、非常に便利できることがわかりました!今回、クラウド側(サーバ側)のコードは1行も書いていないので、ここまでのことがAmplifyだけで完結できるのはすごいですね。まだまだ使えていないコンポーネントがあるので、他も一通り使ってみたいと思っています!

ユーザー管理も、今後は自前で作らず、全部Cognitoに任せちゃったら楽ですね。今回は使わなかったのですが、SNSログインのOAuthは自前での実装はかなり面倒なので、その部分だけでもCognitoを使うメリットは十分あると思いました。

前回から紹介しているAppSync、学習のためにGraphQLを使っていますが、RESTのAPIも作成できます。そのどちらにおいてもインターフェイスのドキュメントが自動生成されコンソールで確認できます。APIのドキュメント作成/管理から開放されるのも助かります。

本当は、GraphQLのsubscription機能を使って、サーバープッシュができるリアルタイムなアプリを考えていたのですが、内容的にてんこ盛りになってしまったので、今回はここまでにして、次回、subscriptionを使ったアプリを作成したいと思います。

 

Pocket
LINEで送る