AWS Amplify + Vue.js触ってみる

IT記事

AWS Amplify触ってみる。速攻でApi形式のWebアプリ作れる。色々できてすごいぞ。

今回はVue.jsチュートリアルをやってみる。

まずはvue cliでプロジェクトを作る。

vue create amplifytest

次にamplify cliのインストールと設定。

npm install -g @aws-amplify/cli
amplify configure

configureではログインとか、IAMでルートユーザーを作らされる。途中でブラウザが開くので操作をして完了したら、コマンドに戻って進める。

次にvue cliで作ったプロジェクトに移動

cd amplifytest

ここからamplicy cliを使って、設定をしていく。まずプロジェクト全体のAWS 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 amplifytest
? Enter a name for the environment test
? 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:  npm.cmd run-script build
? Start Command: npm.cmd run-script 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 (Use arrow keys)
> default (node:9952) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 keypress listeners add
? Please choose the profile you want to use default

プロジェクトの名前とか、vueを使いますよとか設定していく。

今度はAmplifyで使う機能を設定する。ここで使うのはバックエンドapiをGraphQLかRESTで作ってくれるAPIという機能。

amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: amplifytest
? Choose the default authorization type for the API API key
? Enter a description for the API key: amplifytest
? After how many days from now the API key should expire (1-365): 7
? 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: (Use arrow keys)
> Single object with fields (e.g., “Todo” with ID, name, description)
? 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

GraphQLを選び、認証方法をとりあえずapi keyを選んだ。後からも変えられるようだ。GraphQLの定義(スキーマ)を編集したりできるそうだ。用意してくれているTodoスキーマをそのまま使う。

設定をしたので、実際にawsに作ってもらう。

amplify push
? 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

なんか聞かれるがまだよくわからないな。

以下のコマンドで作ったapiが見れる。AWSのAWS AppSyncというサービスで作られたようだ。

amplify console api

Vue.jsからAmplifyする

よし次はVue.jsだ。まずVue用のAmplifyコンポーネントをインストールする。こんなものまで用意してくれているなんて最近のサービスはすごいな。

npm i aws-amplify
npm i aws-amplify-vue

読み込むコードを書く。よくわからないからコピペだ。

import Vue from "vue";
import App from "./App.vue";
import router from "./router";

Vue.config.productionTip = false;

// aws amplify
import Amplify, * as AmplifyModules from "aws-amplify";
import { AmplifyPlugin } from "aws-amplify-vue";
import awsconfig from "./aws-exports";
Amplify.configure(awsconfig);
Vue.use(AmplifyPlugin, AmplifyModules);

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

AWS AmplifyのドキュメントのVueのページにあるコードを書いてみる。

目標は、Todoを作成したら、それを感知して画面に反映する。(create,subscribe)

つまりtodo書いたら画面に反映される。複数ユーザーが書いても反映される。

<template>
  <div class="home">
    <amplify-connect
      :query="listTodosQuery"
      :subscription="createTodoSubscription"
      :onSubscriptionMsg="onCreateTodo"
    >
      <template slot-scope="{loading, data, errors}">
        <div v-if="loading">Loading...</div>

        <div v-else-if="errors.length > 0">Error!</div>

        <div v-else-if="data">
          <ul>
            <li v-for="item in data.listTodos.items" v-bind:key="item.id">
              <span>{{item.id}} - {{item.name}} - {{item.description}}</span>
            </li>
          </ul>
        </div>
      </template>
    </amplify-connect>

    <amplify-connect :mutation="createTodoMutation" @done="onCreateFinished">
      <template slot-scope="{ loading, mutate, errors }">
        <div v-else-if="errors.length > 0">Error!</div>
        <input v-model="form.name" placeholder="item name" />
        <input v-model="form.description" placeholder="item description" />
        <button :disabled="loading" @click="mutate">Create Todo</button>
      </template>
    </amplify-connect>
  </div>
</template>

<script>
const ListTodosQuery = `query ListTodos {
    listTodos {
      items {
        id
        name
        description
      }
    }
  }`;

const OnCreateTodoSubscription = `subscription OnCreateTodo {
      onCreateTodo {
        id
        name
        description
      }
    }`;

const CreateTodoMutation = `mutation CreateTodo($name: String!, $description: String) {
    createTodo(input: { name: $name, description: $description }) {
      id
      name
      description
    }
  }`;

export default {
  name: "Home",

  data() {
    return {
      form: { name: "", description: "" }
    };
  },

  computed: {
    listTodosQuery() {
      return this.$Amplify.graphqlOperation(ListTodosQuery);
    },
    createTodoSubscription() {
      return this.$Amplify.graphqlOperation(OnCreateTodoSubscription);
    },
    createTodoMutation() {
      return this.$Amplify.graphqlOperation(CreateTodoMutation, {
        name: this.form.name,
        description: this.form.description
      });
    }
  },
  methods: {
    onCreateTodo(prevData, newData) {
      console.log("New todo from subscription...");
      const newTodo = newData.onCreateTodo;
      prevData.data.listTodos.items.push(newTodo);
      return prevData.data;
    },
    onCreateFinished() {
      console.log("Todo created!");
    }
  }
};
</script>

できた。

動くとテンション上がる。すぐこんなの作れるのはすごいな。