Vue.js＋Amplifyを駆使すればモダンなWebアプリを20分で公開できる

# SPA -> GraphQL -> Serverlessバックエンド
Vue.jsとAmplifyを駆使して、1からモダンなフロントエンド開発＆サーバレスバックエンド構築をしてきます。今回は、Vue.jsで作成したSPAからAppSyncへGraphQLベースのリクエストを送り、裏のDynamoDBへデータの書き込みと読み込みまでを確認します。

（完成図）
![Untitled Diagram (1).png](https://qiita-image-store.s3.amazonaws.com/0/206255/834eafdb-7bfe-03fd-1f1a-16d8ff6e53fe.png)

バックエンドのAWSリソースは、Amplify Frameworkを使用することで、コマンドラインから作成していきます。

また、Amplify Consoleを使用することで、CI/CDパイプラインも同時に作成し、GitHub上の最新断面がHTTPSでWebアプリとして公開するまでが本記事のゴールです。
![Untitled Diagram-Page-2.png](https://qiita-image-store.s3.amazonaws.com/0/206255/15e0fa7f-c048-e08b-db0b-66be8258b118.png)


## 登場人物

### Vue.js
小さなアプリから大規模まで対応できる優れたフロントエンドフレームワークで、個人的にも多用しています。本記事はVue.jsのAdventCalendar10日目として公開しています。

### Buefy
BuefyはBulmaというUIライブラリをVueで使いやすくしたものです。普段はElementUIを使うことが多いですが、今回はBuefyを使用してみました。100％レスポンシブ対応している点が特徴です。
:pencil: [Bulma公式ページ](https://bulma.io/)

### Amplify Framework
クラウドネイティブなWebアプリを開発しやすくするライブラリを提供してくれます。Angular、React、Vueそれぞれに対応しています。Vue.js用の使用方法を説明している公式ページはこちら。
:pencil: [Amplify JavaScript for Vue](https://aws-amplify.github.io/docs/js/vue)

### Amplify Console
AWSのイベントであるre:Invent2018で新たに発表されたサービスで、Webアプリを公開する環境を簡単に準備できる機能が追加されました。CI/CD機能に加え、CDN機能も提供してくれます。本記事で詳しく見ていきます。

### AppSync
AWSのGraphQLマネージドサービスです。Vue.jsからリクエストをGraphQLで受け取ります。
:pencil: [GraphQL入門 (AWS AppSync)](https://www.slideshare.net/AmazonWebServicesJapan/graphql-aws-appsync)

### DynamoDB
AWSのNoSQLデータベースサービスで、AppSyncの裏に配置してデータの保存先として利用します。
:pencil: [[公式]DynamoDBとは](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Introduction.html)

### GitHub
Vue.jsのソースコードを管理します。GitHubのmasterブランチにソースコードがプッシュされたことをトリガーにWebアプリが公開されるようにします。本記事ではGitHubの取り扱いについては省略します。

# 準備

## Apmlifiy CLIのインストール(0.5分)

Amplify CLIをインストールために下記コマンドを実行してください。

```bash:amplifyのインストール
$ npm install -g @aws-amplify/cli
```

「AWS AMPLIFY」が表示されればOKです。

```bash
$ amplify

  █████╗  ██╗    ██╗ ███████╗      █████╗  ███╗   ███╗ ██████╗  ██╗      ██╗ ███████╗ ██╗   ██╗ 
 ██╔══██╗ ██║    ██║ ██╔════╝     ██╔══██╗ ████╗ ████║ ██╔══██╗ ██║      ██║ ██╔════╝ ╚██╗ ██╔╝ 
 ███████║ ██║ █╗ ██║ ███████╗     ███████║ ██╔████╔██║ ██████╔╝ ██║      ██║ █████╗    ╚████╔╝  
 ██╔══██║ ██║███╗██║ ╚════██║     ██╔══██║ ██║╚██╔╝██║ ██╔═══╝  ██║      ██║ ██╔══╝     ╚██╔╝   
 ██║  ██║ ╚███╔███╔╝ ███████║     ██║  ██║ ██║ ╚═╝ ██║ ██║      ███████╗ ██║ ██║         ██║    
 ╚═╝  ╚═╝  ╚══╝╚══╝  ╚══════╝     ╚═╝  ╚═╝ ╚═╝     ╚═╝ ╚═╝      ╚══════╝ ╚═╝ ╚═╝         ╚═╝    

amplify <command> <subcommand>

...
```

## Vueプロジェクトの作成(1分)

Vue CLIを使用してVueプロジェクトを作成します。Vue CLIのインストールがお済みでない場合は、以下コマンドを実行します。

```bash:Vue-CLIのインストール
$ npm install -g @vue/cli
```

※[参考] Vue.jsプロジェクト作成手順の手引き
:pencil: [SpringBoot+Vue.js+ElementUI+Firebaseでマスタ管理アプリ入門#Vueプロジェクトの作成](https://qiita.com/shunp/items/abea7fa01e7a664c85da#vue%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90)

`vue create`でプロジェクトを作成していきましょう。今回は牡羊座の「Aries」というプロジェクト名にします。

```bash:Vue.jsのプロジェクト作成
$ vue create aries
```

`http://localhost:8080/`でサンプル画面が表示されれば成功です。

## ライブラリのインストール(0.5分)

必要になるモジュールをインストールしておきます。今回のアプリでは機能を限定しているので、amplify系とUIライブラリのbuefyの他は特に必要ありません。

```bash:各種ライブラリのインストール
$ npm i --save aws-amplify
$ npm i --save aws-amplify-vue
$ npm i --save buefy
```

vue-createしたファイルは個人のGitHubにプッシュしておきましょう。

```bash:GitHubへコミット
$ git add .
$ git commit -m "first commit"
$ git push origin master
```

ここまでで準備は完了です。特段問題がなければトータル2分程度で終わります。

# バックエンドの構築

## Amplify FrameworkでAWSリソースの準備(3分)
ここからはAWSを利用して、amplifyを使ったリソースの構築をしていきます。まずは初期セットアップを行うために、以下コマンドを実行します。

```
$ amplify init

? 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 run-script build
? Start Command: npm run-script serve
```

Yes/Noの選択がいくつかありますが、基本的にデフォルトの設定で問題ありません。言語とフレームワークはJavaScript/Vueを必ず選択します。

※AWS-CLIの設定が済んでいない場合は、リージョンやアクセスキーの設定をコマンドラインから行う必要があります。下記にも手順がありますので設定を進めてください。

:pencil: [Amplify JavaScript # amplify configure](https://aws-amplify.github.io/docs/cli/init#amplify-configure)

次に、APIのエンドポイントを作成していきます。下記コマンドを実行してください。

```
$ amplify add api

? Please select from one of the below mentioned services GraphQL
? Provide API name: aries
? Choose an authorization type for the API API key
? 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
```

今回はGraphQLベースで作成していきます。Authorizationタイプは簡略化するためAPI KEYを選択します。Schemaも編集せず、今回はデフォルトのTodoをそのまま使用していきます。

最後に、以下コマンドでAWSリソースを作成していきます。

```
$ amplify push

| Category | Resource name | Operation | Provider plugin   |
| -------- | ------------- | --------- | ----------------- |
| Api      | aries         | Create    | awscloudformation |

? 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
```

CloudFormationによりAppSyncとDynamoDBが自動生成されていることがターミナルから確認できると思います。基本的に選択肢は全てデフォルトです。

GraphQLのエンドポイントとAPI KEYがターミナルに表示されたら成功です。

## AWSコンソールで作成されたリソースの確認(1分)

AWSのコンソールから、AppSyncを選択して作成物を確認します。API一覧の中に、今回作成した「aries」が存在しています。

![FireShot Capture 98 - AWS AppSync Console_ - https___console.aws.amazon.com_appsync_home.png](https://qiita-image-store.s3.amazonaws.com/0/206255/019cc917-9bf9-1c9d-b914-110eb1db341e.png)

右側の「Data Sources」をクリックすると、一緒に作成されたDynamoDBを確認することができます。当然、今の段階ではデータベースは空です。

![FireShot Capture 99 - AWS AppSync Console_ - https___console.aws.amazon.com_appsync_home.png](https://qiita-image-store.s3.amazonaws.com/0/206255/96aafa3b-13bb-8481-0875-a0a02bafe5d9.png)

# デプロイパイプラインの構築

## Amplify Consoleからアプリ環境の作成(3分)

AWSコンソールから「Amplify Console」を選択し、「connect app」ボタンからアプリ環境の作成を行います。Step1でソースコードを管理しているリポジトリを選択しますが、今回は既にVue.jsのソースコードがコミットされているGitHubを選択していきます。

![FireShot Capture 100 - AWS Amplify Console_ - https___console.aws.amazon.com_amplify_home.png](https://qiita-image-store.s3.amazonaws.com/0/206255/c65b807f-0ee2-b935-c8d2-15d09fecf7a0.png)

Step2ではリポジトリ名とブランチ名を指定します。

![FireShot Capture 101 - AWS Amplify Console_ - https___console.aws.amazon.com_amplify_home.png](https://qiita-image-store.s3.amazonaws.com/0/206255/68af37ce-1f5d-9b18-9b3f-fc9ecf855425.png)

Step3、Step4は特に変更するところはないので画面の指示通り進めます。

作成が完了したら、左メニューからビルド設定のYAMLファイルを確認してください。

![FireShot Capture 102 - AWS Amplify Console_ - https___console.aws.amazon.com_amplify_home.png](https://qiita-image-store.s3.amazonaws.com/0/206255/8496f6e6-3325-2719-7fb2-15a48c85289b.png)


```yml:amplify.yml
version: 0.1
frontend:
  phases:
    preBuild:
      commands:
        - npm ci
    build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: dist
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
```

以上の設定で、GitHubのソースコードが変更されるたびにデプロイされるパイプラインが完成しました。

![FireShot Capture 103 - AWS Amplify Console_ - https___console.aws.amazon.com_amplify_home.png](https://qiita-image-store.s3.amazonaws.com/0/206255/be0a06bd-c2ab-fb65-33b8-6c1825e33e4b.png)

画面に表示されているURLから確認してみましょう。HTTPSでWebに公開されていることが確認できれば成功です。


## Amplifyの設定をVue.jsに追加する(1分)

現段階では`vue create`で作成したデフォルトの画面が表示されるため、新たにCRUD操作を行うためのページを用意していきましょう。まずはAmplifyをVueで使用できるように以下のように修正します。

```javascript:main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

import Amplify, * as AmplifyModules from 'aws-amplify' // 追記
import { AmplifyPlugin } from 'aws-amplify-vue' // 追記
import aws_exports from './aws-exports' // 追記
Amplify.configure(aws_exports) // 追記

Vue.use(AmplifyPlugin, AmplifyModules) // 追記

Vue.config.productionTip = false

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

## 新たなページの追加とルーティングの変更(8分)

TODO項目を画面から追加できるよう、新たなページを作成していきます。

まずは、ルーティングを変更しましょう。`/`でアクセスした場合に今回追加するTODO管理ページに遷移するよう修正します。

```javascript:router.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    // {
    //   path: '/',
    //   name: 'home',
    //   component: Home
    // },
    {
      path: '/',
      name: 'todo',
      component: () => import(/* webpackChunkName: "todo" */ './views/Todo.vue')
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})
```

既に記述されているHomeへのアクセスはコメントアウトしておきます。

次に、`Todo.vue`ファイルを作成していきます。

GraphQLを使用して、データの登録と一覧取得を行います。Amplifyを使用することで、既にクエリは`src/graphql`以下に自動生成されているため、新たにGraphQLのクエリを記述する必要はありません。`graphqlOperation`を使用して、簡単にAPIコールを行うことができます。

```vue:Todo.vue
<template>
  <div>
    <nav class="level">
      <div class="level-item has-text-centered">
        <div>
          <p class="heading">TODO</p>
          <b-field label="Name">
            <b-input v-model="input.name"></b-input>
          </b-field>
        </div>
      </div>
      <div class="level-item has-text-centered">
        <div>
          <b-field label="Description">
            <b-input v-model="input.description"></b-input>
          </b-field>
        </div>
      </div>
    </nav>
    <button class="button is-link" @click="createTodo">ADD</button>
    <ul id="todo">
      <li v-for="todo in todos">
        <span class="todo-wrapper">{{ todo.name }}</span>
      </li>
    </ul>
  </div>
</template>

<script>
import {API, graphqlOperation} from 'aws-amplify'
import * as mutations from '@/graphql/mutations'
import * as queries from '@/graphql/queries'

export default {
  name: 'todo',
    data: function () {
    return {
      input: {
        name: '',
        description: ''
      },
      todos: []
    }
  },
  created: async function () {
    await this.listTodos()
    
  },
  methods: {
    createTodo: async function () {
      if (this.input.name !== '' || this.input.description !== '') {
        await API.graphql(graphqlOperation(mutations.createTodo, {input: this.input}))
         .catch(err => console.error(err))
        await this.listTodos()
      } else {
        console.info('input empty')
      }
    },
    listTodos: async function () {
      const res = await API.graphql(graphqlOperation(queries.listTodos))
        .catch(err => console.error(err))
      this.todos = res.data.listTodos.items
    }
  }
}
</script>
<style scoped>
.todo-wrapper {
  /* 適宜記述 */
}
</style>
```

入力フォームにTODO名と説明を入力し「ADD」ボタンを実行すると、`createTodo`メソッドが実行されます。`mutations`はGraphQLで更新を行う場合に使用されますが、AppSyncへリクエストがとび、そのままDynamoDBへデータが書き込まれます。また、`queries`はGraphQLの取得を行う場合に使用されますが、AppSyncへリクエストが飛んだ後、DynamoDBのデータを取得し、画面上にレンダリングします。

気の利いた機能やレイアウトは今回の趣旨から外れるので、今回は実装しません。queriesとmutationsの呼び出し方を参考にしてもらえれば嬉しいです。Buefyを使用しているため、スマホ用のWeb表示も簡単です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/206255/fb27e2ef-bf93-c357-1827-c7f644ae93db.png)

## 公開されたWebページに変更を反映する(2分)

最後に、Webページを更新します。修正したソースコードをGitHubにコミットして、masterブランチにプッシュすると、Amplify Consoleのパイプラインが自動的にビルドを始めます。1分ほど待つとデプロイまで完了し、修正内容が反映されていることがわかるかと思います。

# 最後に

- Amplify Frameworkを使用することで、バックエンドのロジックを一切記述することなくサーバレスで構築することができました。
- Amplify Consoleを使用することで、Vue.jsのCI/CDパイプラインを簡単に構築することができました。
- GraphQLやサーバレスとったモダン要素を取り入れながら、20分でアプリを公開することができました。