vue-cliではじめるWebアプリ制作

## 0. はじめに
この資料はjavascriptの基本的な書き方を学習し終わった方向けに
vue-cli3を使った簡易なWebアプリの作り方を説明するための資料となっています。

内容としては

- vue-cli3の使い方
- 作成されるプロジェクトの概要
- Vue.jsの基本的な機能
- APIサーバーの作成方法
- UIとAPIサーバーの通信方法

を含み、またおまけとして

- ibmcloudのcloudfoundryを用いたwebへのデプロイ方法
- Watson Assistantを用いたチャットボットアプリへの拡張

を含みます。

抜け、漏れや間違いなどございましたらコメントでご指摘いただけますと幸いです。

## 1. 環境構築
### 実施環境
今回のプロジェクトは以下のような環境で作成しました。

``` 
mac : Big Sur 11.5
google chrome :  92.0
npm : 7.18.1
node : v16.4.1
@vue/cli : 4.5.13
ibmcloud cli : 1.5.1
```

### node.jsの導入
この辺りを参考にnode.jsを導入してください。
[MacにNode.jsをインストール](https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09)
[node.js公式サイト](https://nodejs.org/en/download/)

### vue-cli3の導入
ターミナル（windowsならPowershell）を開いて次のコマンドを実行してください。

```
npm install -g @vue/cli
```

完了したら次のコマンドを実行してインストールが正しく行えたか確認してください。

```
vue --version
```

次のようにバージョンが表示されたらインストール成功です。

```
@vue/cli 4.5.13
```

環境構築はここまで


## 2. アプリの作成

アプリを置いておきたいディレクトリに移動して次のコマンドを実行してください
（フォルダごと作成されるので専用のフォルダなどを作る必要はありません）

```
vue create <アプリ名>
```

以下は作成時に聞かれる項目の解説です

```
? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 2] babel, eslint)
  Default (Vue 3) ([Vue 3] babel, eslint)
  Manually select features
```

オプションのプリセット、簡単なアプリを作るだけならDefaultでも事足りますが、
今回はよく使う機能の説明も含むので一番下の**Manually select features**を選択してださい。

```
? Check the features needed for your project: (Press <space> to select, <a> to t
oggle all, <i> to invert selection)
❯◉ Choose Vue version
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◯ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing
```

最初から導入しておきたいパッケージを選択します
↑↓キーで選択、Spaceキーで切り替え、Enterキーで完了
今回は**Vue3.0, Babel, Router**のみを有効にしてください

<details><summary>各パッケージの簡単な説明</summary><div>

- Choose Vue version
Vueのバージョンを選択する

- Babel
javascriptの新しい記法を色々なブラウザで使えるようにするパッケージ
参考：[【５分でなんとなく理解！】Babel入門](https://qiita.com/Shagamii/items/a87181c22ea777ee2acc)

- TypeScript
javascriptを拡張した言語
型が明確、継承がサポートされているなど複数人が関わるプロジェクトで役立つ機能が多い

- Progressive Web App (PWA) Support
Webアプリからスマートフォンの一部機能を利用できるようになる機能

- Router
ページを遷移せずに複数のコンテンツを表示するために利用する
SPA(SinglePageApplication、単一のページでコンテンツを表示するwebアプリケーション)の実装に重要

- Vuex
異なるページの間でデータを共有するために利用する

- CSS Pre-processors
SASSなどのCSSを拡張するパッケージ

- Linter / Formatter
インデントや関数の形式などコードの書き方を管理するパッケージを導入する
複数人が関わるプロジェクトではほぼ必須

- Unit Testing
コードの単体テストを行うパッケージを導入する
DevOpsやTDD（テスト駆動開発）で利用されるが、テストコード自体も適切な管理が必要なので注意

- E2E Testing
コードのEndToEndテスト（結合テスト）を実施するパッケージを導入する
注意点はUnitTestと同様

</div></details>

```
? Choose a version of Vue.js that you want to start the project with (Use arrow
keys)
　　 2.x
❯ 3.x
```
Vueのバージョンを選択します。
ネットにある記事は2.0のものが多いですが、
3.0では周辺モジュール（vue-routerなど）の書き方が変わっていたりUIコンポーネント（Bootstrapなど）が一部対応していなかったりするので注意してください。
今回は**3.x**を選択してください。

```
? Use history mode for router? (Requires proper server setup for index fallback
in production) (Y/n)
```

Routerを導入した場合のみ発生、vue-routerをhistoryモードで動かすかどうかについての質問です。
通常Vue-Routerを使用すると各コンテンツのURLは
`http://localhost:8080/#/hoge`
のように # が必要となるが、historyモードを用いると # を省略して
`http://localhost:8080/hoge`
と記述できます

ただし、こちらのモードを利用する場合以下のような仕様があるため注意してください。

- サーバへの通信が発生するため速度が低下する
- アプリをデプロイする際サーバー側で設定が必要
- History APIをサポートしていないブラウザで動作しない

詳細な説明は[こちら](https://router.vuejs.org/ja/guide/essentials/history-mode.html)

今回はhistoryモードを使用しないため、 **n** を入力してください。

```
? Where do you prefer placing config for Babel, ESLint, etc.?
❯ In dedicated config files
  In package.json
```
Babel, ESLintなど各種パッケージの設定をどこで行うかを設定する質問です。
In dedicated config filesでは個別のconfig fileを作成し、
In package.jsonではpackage.jsonでまとめて管理します
今回は **In dedicated config files** を選択してください。

```
? Save this as a preset for future projects? (y/N)
```
今回の設定をプリセットとして保存するかどうかの質問です。
今回は保存しないため **n** を入力しください。

```
? Pick the package manager to use when installing dependencies: (Use arrow keys)

❯ Use Yarn
  Use NPM
```
package管理ツールの選択です。
今回はyarnを使用するので　**Use Yarn** を選択してください。

## 3. 作成されたプロジェクトの確認
### 3.1. プロジェクト構造の確認
次のような構造のプロジェクトが作成されます。
![スクリーンショット 2021-08-27 21.40.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/8f544dad-5fcb-ea2b-eb9c-0b21de37b5f2.png)

<details><summary>各ファイルの説明</summary><div>

- babel.config.js
babelの設定ファイル

- node_modules
npm or yarnでインストールしたパッケージが配置されるフォルダ

- package.json
パッケージの状況やアプリの実行コマンドなどアプリのコンフィグの大部分を管理するファイル

- public
クラウドなどにデプロイするためのビルド済みファイルが配置されるフォルダ

- README.md
アプリの説明文を記入するファイルgitなどのリポジトリで自動表示される

- src
画面ファイルのソースコードが入っているフォルダ

- App.vue
Webアプリのメイン画面を記述するソースコード
全てのコンテンツに共通する内容はここで記述する

- assets
動的な変更を必要としない画像や動画などを配置するフォルダ

- components
画面部品を配置するフォルダ
複数の箇所で使い回す場合や責務の分離が必要な場合、コンポーネントとして分離する

- main.js
Webアプリ起動時に最初に動作するファイル
App.vueなどを呼び出す

- router
vue-routerの設定ファイルが入っているフォルダ

- views
各コンテンツの内容はここで記述する
webページ作成で主に編集するフォルダ

- yarn.lock
yarnにおけるパッケージの依存関係を管理するファイル
package.jsonを変更すると自動で変更される

</div></details>

起動して確認するためには以下のコマンドを実行する

```
yarn serve
```

次のような表示が出たら実行準備完了です。

```
  App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.50.136:8080/

  Note that the development build is not optimized.
  To create a production build, run yarn build.
```

ブラウザを開いて```http://localhost:8080/```にアクセスしてください。
![スクリーンショット 2021-08-27 22.37.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/ffcb8225-ed5f-c6f7-d649-29c7fe44c8a3.png)
このような画面が表示されれば成功です。

アプリを終了するときには
`control + C`　キーを同時押ししてください。

### 3.2. コードを編集してみる
`src/views/Home.vue`をメモ帳,vim,vscodeなどのエディタで開いた後
再度　`yarn serve`でアプリを起動してください。

```vuejs:`src/views/Home.vue`
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>　 //　← ここを編集
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',
  components: {
    HelloWorld
  }
}
</script>
```

`Welcome to Your Vue.js App`を適当な文字列に書き換えて保存してみましょう
![スクリーンショット 2021-08-27 23.58.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/9700019b-0432-0f03-4b42-7e6ce6da67d6.png)
指定した文字列に書き換わりましたね
このように`yarn serve`での起動中にソースコードを書き換えるとアプリケーションに自動で反映されます

### 3.3. routerの確認
アプリを動かしたままもう一つターミナルを開いて
`/src/router/index.js`を開いてみましょう

``` javascript:`/src/router/index.js`
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    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')
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router
```

ここで画面に表示するコンテンツの元になるファイルを指定しています
変数routesに注目してみましょう

``` javascript
import Home from '../views/Home.vue'
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  }
]
```

ここで各コンテンツのURLと表示する内容を設定しています
それぞれ

- path: URLにおける #以降のアドレス
- name: コンテンツの名前
- component: 表示する元となるファイル

を表します、例えば2個目のaboutならば
`http://localhost:8080/#/about`にアクセスすると`/src/views/About.vue`ファイルを表示することになるわけです
実際に`http://localhost:8080/#/about`にアクセスしてみます。
![スクリーンショット 2021-08-28 0.17.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/b7ce71b6-3260-0a92-d7fb-07f10d44bc59.png)

```vuejs:/src/views/About.vue
<template>
  <div class="about">
    <h1>This is an about page</h1>
  </div>
</template>
```

`/src/views/About.vue`と見比べてみると一致しているのがわかると思います。
(上のHome｜Aboutは`/src/app.vue`に書かれた共通処理)

## 4. Vue.jsの記法
### 4.1. 準備
この項ではVue.jsでよく使う記法について書いていきます
まずテスト用に新しいページを作ります。

`/src/router/index.js`の変数routesに

```javascript
{
    path: '/test',
    name: 'Test',
    component: () => import('../views/Test.vue')
}
```

を追加しましょう。

```javascript
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  },
  {
    path: '/test',
    name: 'Test',
    component: () => import('../views/Test.vue')
  } //これを追加
]
```

この時ブラウザはエラーになりますが一旦放置で大丈夫です。
続いて`/src/views`フォルダに`Test.vue`という名前のファイルを作りましょう。

この時点でブラウザのエラーが解消されるので`http://localhost:8080/#/test`にアクセスします。Home|Aboutだけが表示されている状態になったら準備完了です

まず`Test．vue`に次のように書き込みます

```vuejs:Test.vue
<template>

</template>
<script>
export default {
    name: 'Test',
    components: {},
    methods: {

    },
    data: () => ({
        
    }),
}
</script>
<style>

</style>
```

これがvue.jsでファイルを扱う際の基本形です
`<template> ~ </template>` の範囲がWebページの基本的な構造、仕組みを書く部分
`<script> ~ </script>` の範囲が変数や関数などの処理を書く部分
`<style> ~ </style>` の範囲が見た目の飾り付けを書く部分
となります

`<style>`ブロックは通常のCSSと同じ挙動でクラスなどを用いて見え方を調整することができますが、今回の内容では扱いません。

まず
`<template> ~ </template>`の中に

```vuejs
<div>
    Hello  Vue
</div>
```
と書き込んで保存してみます。

![スクリーンショット 2021-08-28 0.47.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/0decf552-41eb-8c40-b20c-69cd832b4d96.png)
このように書き込んだ文字が表示されたら正しくRoutingできています

### 4.2. 基本機能の確認
vue.jsの基本的な機能をいくつかテストしていきます。

#### 4.2.1.変数の表示

`<script> ~ </script>`の`data: () => ({ ~~~~ })`の中に変数を定義します

``` vuejs
<script>
export default {
    name: 'Test',
    components: {},
    methods: {

    },
    data: () => ({
        testData: 'Vueはじめました' //このように定義
    }),
}
</script>
```

続いて先ほど作った`<div>`ブロックの中に`{{今定義した変数}}`の形で書き込んで保存します。

```vuejs
<template>
    <div>
        {{testData}}
    </div>
</template>
```

画面には先ほど定義した変数の内容が表示されているはずです。
![スクリーンショット 2021-08-28 0.55.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/8e7373ce-c52a-4b6a-ba4d-7afaaa4c92ec.png)
このようにdataで定義した変数を`{{　}}`で囲うことでその値を表示することができます。

#### 4.2.2. タグ属性の操作（v-bind）
htmlタグの属性情報を変数に紐付けて自由に変更できるようにしてみます。
まず、先ほど作った`<div>`ブロックの中に
`<img src="../assets/logo.png" width='100'>`
を記入して保存します。
（この画像は`/src/assets`の中に入っています）

```vuejs
<template>
    <div>
        <img src="../assets/logo.png" width='100'>
    </div>
</template>
```
![スクリーンショット 2021-08-28 12.01.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/8f2616c6-e011-7cf0-e995-03947995e414.png)
このように画像が表示されたと思います。
この時、`src="../assets/logo.png" width='100'`の部分をタグの属性情報と言い、これを変更することで表示する画像や画像のサイズを操作することができます。
試しにwidthを200などに書き換えてみると画像のサイズが倍になることが確認できると思います。

jqueryや素のjavascriptなどを使う場合にはWebページが開かれているときに属性情報を変更するためにはタグを検索して取得、変更するような手順が必要となります。
一方vueでは、属性情報と変数を紐付けておき、変数が変更されたときに属性情報を書き換えることが可能です。

実際にテストしてみます。
まず、4.2.1.と同様変数部分に`imgWidth: 100`を定義します、
その後、`<img src="../assets/logo.png" width='100'>`の`width='100'`を`v-bind:width='imgWidth'`に書き換えてみましょう。

```vuejs:Test.vue
<template>
    <div>
        <img src="../assets/logo.png" v-bind:width='imgWidth'> //属性情報を書き換え
    </div>
</template>
<script>
export default {
    name: 'Test',
    components: {},
    methods: {

    },
    data: () => ({
        imgWidth: 100 //imgWidthを定義
    }),
}
</script>

```

この状態でimgWidthの値をさまざまに切り替えて保存してみましょう。
属性情報を直接書き換えた時のように画像のサイズが切り替わっているのがわかると思います。

このように`v-bind:<属性情報>='<変数名>'`という記法を使うことで
タグの属性情報に変数を紐付けできるわけです。

また、v-bindは省略可能で一般的には`:<属性情報>='<変数名>'`と書くことが多いのでこちらも覚えておくと良いでしょう。
属性情報の紐付けはアプリの見た目を考える段階、特にBootstrapなどのUIコンポーネントを使うようになると使う機会が大きく増えます。

#### 4.2.3.関数の実行（v-on）
関数を定義することでボタンのクリックなど様々なイベントに対して処理を割り当てることができるようになります。

まず実行用のボタンを作ります。
4.2.2.で挿入した`<img>`タグの下に`<input type='button' value='test'>`を追加しましょう。

```vuejs
<template>
    <div>
        <img src="../assets/logo.png" v-bind:width='imgWidth'>
        <input type='button' value='test'>
    </div>
</template>
```
![スクリーンショット 2021-08-28 13.00.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/3f7105fa-160c-ebb8-e5cd-d5f828ac81ad.png)

図のように画像の下にボタンが表示されたはずです。
今はこのボタンを押しても何も起こりません。これからこのボタンに処理を追加していきます。

続いて、`<script>`ブロックの`methods:{}`の中に関数を定義します。
関数は

```javascript
書き方１
関数名(){
     〜処理〜
}
```

```javascript
書き方２
関数名: function(){
     〜処理〜
}
```
のような形で定義することができます。
どちらを選んでも良いですが、コードの中で複数の書き方を混在させないようにしましょう。

今回はボタンを押したときに画像のサイズを変更する処理を実装したいと思います。

```javascript
changeImgSize(){
    this.imgWidth = 200
}
```
このとき、`data`にある変数は`this.変数`の形で記入してください
（関数の中で他の関数を呼び出す場合も同様に`this.関数`の形で書きます）

では、定義した関数をボタンで呼び出せるようにします。
`<input type='button' value='test'>`に
`v-on:click='changeImgSize'`を追加します。

```vuejs
<template>
    <div>
        <img src="../assets/logo.png" :width='imgWidth'>
        <input type='button' value='test' v-on:click='changeImgSize'>
    </div>
</template>
```
保存してtestボタンをクリックしてみましょう。
![スクリーンショット 2021-08-28 13.31.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/08292f48-7cbd-3648-1683-9dbbf899b68a.png)
図のように画像サイズが大きくなったはずです。

このように`v-on:<イベント>='<関数>'`という記法を使うことでクリックやテキスト入力、マウスオンなどのイベントに対して関数を紐づけることができるようになりました。

こちらの`v-on`も省略記法があり`@<イベント>='<関数>'`の形で書くことができます。
また、今回関数を`'changeImgSize'`と( )のない形で書きましたが、`'changeImgSize(変数)'`のように書くことで通常の変数ありの関数も扱うことができます。

イベントの種類は[この辺り](https://developer.mozilla.org/ja/docs/Web/Events)を参考にしてください。

ここで、関数を扱う上で重要なデバッグ機能について追記しておきます。
javascriptで変数の途中の状態や関数が実行されているかどうかを確認する方法の一つとして`console.log`があります。これを関数内で実行することで、指定した変数や文字列をコンソールに表示することが可能です。
例）

```javascript
changeImgSize(){
    this.imgWidth = 200
    console.log(this.imgWidth) //imgWidthの値を表示
}
```

この時、`console.log`の結果が表示されるのは`yarn serve`が動いているターミナルではなくブラウザのデバッグコンソールです。

![スクリーンショット 2021-08-28 18.16.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/997a1176-6598-ff2e-6169-b437bc3aa513.png)

これはブラウザを開いた状態で
mac：`command + option + i`
windows：`Ctrl + Shift + i`
を押すと開くもので、コンソールの確認の他にもスマホなどでの見え方の確認やCSSの調整など様々な機能がありますのでwebアプリを作る時には必ず確認するようにしましょう。

#### 4.2.4. 繰り返し表示（v-for）
チャットや一覧表示のようにコンテンツを繰り返し表示する必要がある場合、
vueではv-forという記法を用いて書くことができます。

まず、data内に`testArray: ['テキスト１','テキスト２','テキスト３']`という配列を定義します。
続いて<template>ブロック内に

```vuejs
<div v-for="data in testArray">
    {{data}}
</div>
```
を追加します。

```vuejs:Test.vue
<template>
    <div v-for="data in testArray">
        {{data}}
    </div>
</template>
<script>
export default {
    name: 'Test',
    components: {},
    methods: {},
    data: () => ({
        testArray: [
            'テキスト１',
            'テキスト２',
            'テキスト３'
        ]
    }),
}
</script>
```
![スクリーンショット 2021-08-28 14.17.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/91d1256a-1cac-d5cd-cb08-334b28df7df4.png)
図のように配列の内容が表示されたら成功です。

`v-for`は指定したブロックを配列内の要素分繰り返す記法です、
確認のため作成した`<div>`ブロックの中に
`<img src="../assets/logo.png" width='50'>`
を記入してみます。

```vuejs
<template>
    <div v-for="data in testArray">
        {{data}}
        <img src="../assets/logo.png" width='50'>
    </div>
</template>
```
![スクリーンショット 2021-08-28 14.24.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/e5e6ec64-c56e-8e2e-af54-1f42626efb1d.png)
このように`v-for`で指定したブロックの中身が繰り返されていることがわかります。

また、次のように配列内にオブジェクトを指定すると`v-for`ブロック内で表示する内容を変更することができます。

```javascript
testArray: [
    {
        text: 'タイトル１',
        width: '50'
    },
    {
        text: 'タイトル2',
        width: '100'
    },
    {
        text: 'タイトル3',
        width: '200'
    },
]
```

例として以下のように書くと

```vuejs
<template>
    <div v-for="data in testArray">
        {{data.text}}
        <img src="../assets/logo.png" :width='data.width'>
    </div>
</template>
```
testArrayから取り出されたObjectが`data`に代入され、`data.text`、`data.width`の形で値を取り出すことができます。
このサンプルの結果は図のようになります。
![スクリーンショット 2021-08-28 14.32.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/a9aaba57-8018-07f8-148c-986712925108.png)

このように`v-for='<取り出し先> in <配列>'`という記法を使うことでhtml要素を配列の要素分繰り返すことができるようになりました。

####4.2.5. 変数の同期（v-model）
4.2.2.のv-bindで属性情報に変数を紐付けました。
v-bindは変数が変わった際にhtml要素を操作することができますが、html要素を変更した場合に変数を変更することはできません。
例として以下のような`<input>`タグの挙動を試します

```vuejs
<template>
    <div>
        {{testData}}
    </div>
    <div>
        <input type='text' :value='testData'>
    </div>
</template>
<script>
export default {
    name: 'Test',
    components: {},
    methods: {},
    data: () => ({
        testData: 'テスト'
    }),
}
</script>
```

この時、上の表示欄と下の入力欄の両方に`テスト`が表示されていますが、
![スクリーンショット 2021-08-28 14.50.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/7ab66d77-ca63-ec94-ef77-8f4a8b760786.png)
入力欄を書き換えた場合、
![スクリーンショット 2021-08-28 14.51.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/869b48b2-99b2-f8d8-8ddb-750acae21f31.png)
書き換え欄と入力欄が一致しません。
このようにhtmlへの入力を変数に反映させるためには`v-model`という記法を使います。
`<input>`ブロックの`:value`を`v-model`に書き換えて保存し、ブラウザを更新してください。
![スクリーンショット 2021-08-28 15.10.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/4194641e-29c3-b1de-ec24-20047673d544.png)
入力欄を書き換えると表示欄の内容が同時に書き変わるようになるはずです。

このように、`v-model='<変数>'`という記法を使うことでhtml要素と変数を同期させることができるようになります。

なお、入力を同期させたい場合には`@change='変数に入力を代入する関数'`のような方法で代用することも可能です。v-modelとchangeイベントは同時に使えないため、入力時に複数の処理を行いたい場合にはこちらを利用するのが良いと思います。

#### 4.2.6. 要素の使い回し（コンポーネント）
vueではvueファイルの中で他のvueファイルを呼び出してコンポーネント（部品）として扱うことができます。
これによって色々なページで使い回す要素（ヘッダーやフッターなど）やv-for内で繰り返す要素を分割して管理することができます。
これを試すために
`/src/components`に`TestComponent.vue`というファイルを作って以下のように書き込んでください。

```vuejs:/src/components/TestComponent.vue
<template>
    <div>
        コンポーネント
    </div>
</template>
<script>
export default {
    name: 'TestComponent',
    props: {
    },
    methods: {},
    data: () => ({

    }),
}
</script>
```

続いて、`Test.vue`における`<script>`ブロックに`import TestComponent from '@/components/TestComponent.vue'`を書き込んでください。
また、methodsの上に`components: { TestComponent },`を作成します。
完成形はこのようになります。

```vuejs:Test.vue
<script>
import TestComponent from '@/components/TestComponent.vue'

export default {
    name: 'Test',
    components: {
        TestComponent
    },
    methods: {},
    data: () => ({
    }),
}
</script>
```

これで先ほど`TestComponent.vue`で定義したコンポーネントを利用できるようになりました。
続いて`<template>`ブロックの中に読み込んだ`<TestComponent>`でブロックを作ります。

```vuejs:Test.vue
<template>
    <div>
        <TestComponent>
        </TestComponent>
    </div>
</template>
```
![スクリーンショット 2021-08-28 15.52.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/efa8f192-d5eb-744d-e240-7ba93016a422.png)
コンポーネントの内容が`Test．vue`のページに反映されました。

コンポーネントは通常のhtml要素同様に属性情報を渡すことが可能です。
`TestComponent.vue`のpropsオブジェクトの中に`msg: String`を追加してみましょう
この時、Stringは入力をString型で行うことを表します。

また、`<template>`ブロックに`msg`を表示する記述を追加します。
完成形はこのようになります。

```vuejs:/src/components/TestComponent.vue
<template>
    <div>
        コンポーネント:{{msg}}
    </div>
</template>
<script>
export default {
    name: 'TestComponent',
    props: {
        msg: String
    },
    methods: {},
    data: () => ({

    }),
}
</script>
```
続けて、`Test.vue`　の`<TestComponent>`ブロックに`msg='親コンポーネントからの入力'`という属性情報を追加しましょう。

```vuejs:Test.vue
<template>
    <div>
        <TestComponent msg='親コンポーネントからの入力'>
        </TestComponent>
    </div>
</template>
```
![スクリーンショット 2021-08-28 16.01.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/3c2736b4-a4e4-8555-5d1e-c1b1afa1f373.png)
図のように`Test.vue`で入力した内容が`TestComponent.vue`に反映されて表示されます。

このように、Componentを使うことで複数回使う要素を一回で記述したり、ページを部品ごとに分担して作成することができるようになります。
これはvueに限らずAngularなど他のフレームワークでも多用されるテクニックなので覚えておくと良いと思います。

## 5.APIサーバーの作成
ここからはUI側の表示ではなく、ファイル操作や認証を伴うAPIの呼び出し、DB操作などサーバー側で行う処理を作っていきます。
まず、`yarn serve`が動いている場合には`Ctrl + C`で停止してください。
続けて作成したプロジェクトの`package.json`が入っているディレクトリで`vue add express`を実行してください。
（プロジェクト内であればどこでも実行できますが説明を簡単にするためにこのようにします。）

このような表示が出てきた場合にはyを入力してください

```
 WARN  There are uncommitted changes in the current repository, it's recommended to commit or stash them first.
? Still proceed? (y/N)
```
続いてこのような表記が出るのでyを入力してください

```
? Should serve vue app? (Y/n)
```
最後にこのような表記が出るので、サーバー機能を保存したいフォルダ名を入力してください。
（今回はそのまま実行しsrvディレクトリに保存）

```
? Where will be located your server? (./srv)
```
ディレクトリを確認すると今入力した名前のフォルダができているはずなので、中に入っている`index.js`を開きましょう。

```javascript:/srv/index.js
import express from 'express';
// import socketIO from "socket.io";

export default (app, http) => {
  // app.use(express.json());
  //
  // app.get('/foo', (req, res) => {
  //   res.json({msg: 'foo'});
  // });
  //
  // app.post('/bar', (req, res) => {
  //   res.json(req.body);
  // });
  // 
  // optional support for socket.io
  // 
  // let io = socketIO(http);
  // io.on("connection", client => {
  //   client.on("message", function(data) {
  //     // do something
  //   });
  //   client.emit("message", "Welcome");
  // });
}
```
中にはサンプルが入っていますが、socket.ioは今回使わないため削除し、そのほかのコメントアウトされた箇所を戻します。
（socket.ioはリアルタイムの情報通信を可能にする接続形式です。
　チャットなどを作る場合には非常に便利なので気になる方は調べてみてください）

```javascript:/srv/index.js
import express from 'express';

export default (app, http) => {
  app.use(express.json());
  
  app.get('/foo', (req, res) => {
    res.json({msg: 'foo'});
  });
  
  app.post('/bar', (req, res) => {
    res.json(req.body);
  });
}
```
これでサーバー側機能の基本形は完成です。
`yarn express`でサーバーを起動し、`http://localhost:3000/foo`にアクセスしてみましょう
![スクリーンショット 2021-08-28 16.38.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/24083dfe-99b6-8690-d36c-6cf444a8aeef.png)
図のように表示されたと思います。
`/srv/index.js`で定義された

```javascript
  app.get('/foo', (req, res) => {
    res.json({msg: 'foo'});
  });
```
と比較してみると一致しているのがわかると思います。
こちらもUI同様、起動中に書き換えた内容は即座に反映されるため、
内容を書き換えて画面を更新すると書き換えた内容が表示されるようになります。

このように作成したAPIをテストする場合には主にブラウザの拡張機能が利用できます。
例）
Chlome：[Talend API Tester](https://chrome.google.com/webstore/detail/talend-api-tester-free-ed/aejoelaoggembcahagimdiliamlcdmfm?hl=ja)
Firefox：[RESTClient](https://addons.mozilla.org/en-US/firefox/addon/restclient/)

Talend Api Testerの動作例
SCHEMAにURLを設定し、BODYに送る内容を記入してSendボタンを押すとテストできます。
![スクリーンショット 2021-08-28 16.50.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/13769a81-4f3e-57a7-8fce-601f4f08edb2.png)
結果はこのようになります。
![スクリーンショット 2021-08-28 16.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/6ddffd09-ce03-152e-db60-b606a74a60f3.png)

## 6.UIとServerの通信
最後に、UIからServer側で作成したAPIを呼び出せるようにします。
このような通信を行うパッケージはいくつかありますが、今回はaxiosというパッケージを使います。
まず、ServerとUIの両方を`Ctrl + C`で停止させた上で
`yarn add axios vue-axios`
を実行してください。

続けて、`/src/main.js`を開き、下のように書き換えてください。

```javascript:/src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import axios from 'axios' //追加
import VueAxios from 'vue-axios' //追加

createApp(App)
    .use(router)
    .use(VueAxios, axios) //追加
    .mount('#app')
```

完了したら保存して閉じ、次に`vue.config.js`を開いてください。
こちらには`devServer: { proxy: 'http://localhost:3000' }`を追加して保存します。

```javascript:/vue.config.js
module.exports = {
  pluginOptions: {
    express: {
      shouldServeApp: true,
      serverDir: './srv'
    }
  },
  devServer: {
    proxy: 'http://localhost:3000',
  } //追加
}
```

この処理は開発環境の時(yarn serveの時)このserverから外にアクセスした際に自動で
API Serverが動いているポートにアクセスできるようにするための設定です。
詳細は省きますが、このように設定しないとAPIへのアクセスができません。
興味のある方はCORSで調べてみてください。

以上が完了したら`/src/Test．vue`をエディタで表示した上で、
`yarn serve`　及び `yarn express`　を二つのターミナルを使って同時に実行してください。

vue-axiosを導入するとAPIの呼び出しを下のような形で行うことができます。

```javascript
this.axios.get('/<apiのURL>')
    .then((res) => {
         処理
    }).catch((err) => {
         エラー時の処理
    })
```

この時、APIの呼び出しは非同期で行われます。
つまり、 

``` javascript
let test = '呼び出し前の値'
this.axios.get('/<apiのURL>')
    .then((res) => {
         test = '呼び出し後の値'
    })
console.log(test)
```
のように書いた場合`console.log`で表示されるのは'呼び出し前の値'になります。
もし、APIを呼び出した後の処理を使って処理を続けたい場合は

```javascript
this.axios.get('/<apiのURL>')
    .then((res) => {
         処理1
    }).then((res) => {
         処理2
    }).then((res) => {
         処理3
    }).catch((err) => {
         エラー時の処理
    })
```
のように書く必要があります。

このように`then`,`catch`を使って同期処理・エラーハンドリングを行う書き方はPromiseという機能に従ったもので処理を正しい順序で行うために**非常に重要**な機能なので、拡張形である`async`,`await`と合わせて覚えておいてください。

また、`then()`の中で利用されている

```javascript
() => {
    処理
}
```
のような記法をラムダ式と言い、名前を持たない簡易の関数を定義するための記法です。

```javascript
(入力) => {
    処理
　　　　　　　　return 返り値
}
```
あるいは

```javascript
(入力) => (返り値)
```
の形で書くことができ、Promiseだけでなくfilterやmapといった
プロトタイプ関数を使う際にもよく利用する記法ですので覚えておいてください。

さて、これらを用いてTest．vueをAPIとの通信をテストできるよう書き換えます。

```vuejs:/views/Test.vue
<template>
    <div>
        <input type='text' v-model='sendData'>
    </div>
    <div>
        <input type='button' @click='getMessage' value='受信'>
        <input type='button' @click='sendMessage' value='送信'>
    </div>
    <div>送るテキスト：{{sendData}}</div>
    <div>受け取ったテキスト：{{getData}}</div>
</template>
<script>
export default {
    name: 'Test',
    methods: {
        getMessage(){
            this.axios.get('/foo')
            .then((res) => {
                this.getData = res.data.msg
            })
        },
        sendMessage(){
            this.axios.post('/bar', { msg: this.sendData })
            .then((res) => {
                this.getData = res.data.msg
            })
        }
    },
    data: () => ({
        sendData: '送信するテキスト',
        getData: '受け取ったテキスト'
    }),
}
</script>
```
画面は図のようになります。
![スクリーンショット 2021-08-28 17.59.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/30970964-c493-9a64-448e-9ee1f21456da.png)

`getMessage`関数ではaxiosのget methodを使い、`/foo`の内容を受け取って`getData`変数に代入しています。
`sendMessage`関数ではaxiosのpost methodを使い、`/bar`に対して`sendData`変数を送信し、返り値を`getData`変数に代入しています。
それぞれ挙動をテストしてみてください。

受信を押した時にfooが、送信を押したときに入力と同じ内容が表示されていれば成功です。

受信時
![スクリーンショット 2021-08-28 18.07.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/7868e7ea-8c9c-2c1f-76c2-cb836af5a590.png)
送信時
![スクリーンショット 2021-08-28 18.07.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/9ba4495a-4227-3005-e066-3a78678a8ef6.png)

UIとServerの通信は以上です。
`yarn serve`及び`yarn express`を`Ctrl + C`で停止してください。

## 7. おわりに
ここまで読んでいただきありがとうございました。
Vue.jsはAngular、Reactといった仮想DOMを扱うフレームワークの中で最も学習コストが低いため、他のフレームワークの入り口としても有効なものだと思っています。
この記事の内容が少しでも皆様のお役に立てば幸いです。

今回作成したソースコードは[こちら](https://github.com/highnoRQ/vueFirstStep)に配置しています。

## 8. おまけ１：Croudfoundryへのアップロード
ここでは作成したアプリをIBMcloudにアップロードして誰でもアクセスできるようにする方法を紹介します。
AWSやGCP、Azureなどを使う場合と共通する点もありますが異なる点もあるのでその場合は各自リファレンスを読んで頑張ってください。

#### 8.1. ソースコードのビルド
まず、本番環境にアップロードするファイルを作るため、`yarn build`を実行します。
完了するとプロジェクトの中に`dist`というフォルダが追加されます。
これは現時点のコードをコンパイルして、これ単体で動くようなファイルにまとめたものです。
こちらは`yarn serve`で実行した場合と異なり、ソースコードを書き換えても再度`yarn build`を実行するまで変更されません。

`dist`が確認できたら今度は`yarn express:run`を実行し、`http://localhost:3000/#/test`にアクセスしてみます。
(失敗する場合は`yarn express`が動きっぱなしになっている可能性があります)

`yarn serve`及び`yarn express`を同時に実行していたときと同じ状態になっていると思います。
これは`dist`の中身とRESTapiserverを同時に動かすコマンドで、これが動作するのであれば本番環境でも動作する可能性が高いということになります。

これらの機能はvue-cliのパッケージを使って行われますが、vue-cliはデフォルトでは開発環境のみで動作するようになっています。
そこで、`package.json`を開き、`devDependencies`の内容を全て`dependencies`に移しておきましょう

```json:package.json
{
  "name": "test-project",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "express": "vue-cli-service express:watch",
    "express:run": "vue-cli-service express:run"
  },
  "dependencies": {
    "axios": "^0.21.1",
    "core-js": "^3.6.5",
    "vue": "^3.0.0",
    "vue-axios": "^3.2.5",
    "vue-router": "^4.0.0-0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "vue-cli-plugin-express": "~1.0.2"
  },
  "devDependencies": {}
}
```
#### 8.2. ibmcloudの準備
[IBM Cloud](https://cloud.ibm.com/　)
にログイン

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/67b5099e-bf50-736d-f2a6-1b925c35878d.png)
リソースの作成をクリック

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/21bdf935-97f6-d5c7-2a34-b64affa0902d.png)
CloudFoundryで検索し、CloudFoundryをクリック

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/4274ea65-97b6-81bf-6f3f-1faeb0d7ee1c.png)
作成をクリック

![スクリーンショット 2021-08-28 20.32.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/826f952a-f3ee-a45f-52d5-bf921d6ebe9d.png)
ロケーションをダラスに設定

![スクリーンショット 2021-08-28 20.35.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/b7ebcd79-d599-ac6c-72b0-ea4fcbee1643.png)
リソースを　`SDK for Node.js`を選択
アプリ名を設定

![スクリーンショット 2021-08-28 20.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/a2bf5d52-08ba-3ec0-d5e5-2df654f6636f.png)
作成をクリック
（Liteアカウントで登録している場合、無料で使用することができます。リソースは３０日間経つと削除されます）

以下を参考にIbmcloud cli toolをインストールしてください。
[IBMCloud cli toolのインストール方法](https://cloud.ibm.com/docs/cli?topic=cli-getting-started)

#### 8.3. アプリのデプロイ

プロジェクトの一番上のディレクトリに.cfignoreファイルを作成し、以下の内容を書き込みます。

``` :cfignore
node_modules
yarn.lock
```
このファイルはCloudFoundryにアップロードしないファイルを設定するものです。
node_modulesはCloudFoundryにアップロードした際に自動でインストールされるため、時間短縮のために除外します。
また、yarn.lockは依存関係の都合上、入っているとデプロイに失敗するため除外します。

続いて同じディレクトリにmanifest.ymlファイルを作成し、以下の内容を書き込みます

```yml:manifest.yml
applications:
  - name: <8.2.で設定したアプリ名>
    routes:
      - route: <アプリ名>.<ドメイン名>
    memory: 256M
    disk_quota: 512M
    command: yarn express:run
```
これはCloudFoundryにアップロードする際の設定ファイルです。
ここでCommandを`yarn express:run`に設定することでvue-cliを用いた起動が使えるようになります。
（設定しない場合、`npm start`が利用されます）

`ibmcloud login -r us-south`と打ち込んでibmcloudにログインします。
続いて`ibmcloud target --cf`と打ち込み、cloud foundryをアップデート先に設定します。
最後に`ibmcloud cf push`を入力します

アプリが実行開始できたら
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/de471cc7-a248-009f-f622-0650e557cbaf.png)
アプリURLにアクセスします。

![スクリーンショット 2021-08-28 21.01.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/842f9509-8679-877b-2fd5-a0d3591443b4.png)
作成したアプリがアップロードできていればOKです

## 9. おまけ２：Watson Assistantとの連携
### 9.1. インスタンスの作成
[IBM Cloud](https://cloud.ibm.com/　)
にログイン

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/67b5099e-bf50-736d-f2a6-1b925c35878d.png)
リソースの作成をクリック

![スクリーンショット 2021-08-28 21.09.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/11be4828-9841-dd3d-61d1-8cbf3be1f9a5.png)
Watson Assistantで検索し、Watson Assistantをクリック

![スクリーンショット 2021-08-28 21.10.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/154ce465-29dd-e6a8-1994-9b2125950d0f.png)

ロケーションを適当に設定（CloudFoundryを使う場合は合わせる）
ライトアカウントを選択

![スクリーンショット 2021-08-28 21.10.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/34e2d8aa-dd4c-4284-62dc-c0e7d8c858eb.png)
サービス名を設定

![スクリーンショット 2021-08-28 20.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/a2bf5d52-08ba-3ec0-d5e5-2df654f6636f.png)
作成をクリック

### 9.2.チャットボットの作成

![スクリーンショット 2021-08-28 21.13.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/07fbf616-641b-fad4-2e55-45f5393b0e14.png)
Watson Assistantの起動をクリック

![スクリーンショット 2021-08-28 21.15.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/b4e794d6-cb92-cdc0-bff1-2580f1529331.png)
Create assistantをクリック

![スクリーンショット 2021-08-28 21.15.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/c8fb7ac9-85b8-225a-dc1c-75247ded1e2f.png)
名前を設定してCreate assistantをクリック

![スクリーンショット 2021-08-28 21.16.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/2e36ac8f-90e9-741d-ec55-73889855145f.png)
Add an actions or dialog skillをクリック

![スクリーンショット 2021-08-28 21.19.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/616126a2-8e3f-4c0f-a5c8-51e0a542759e.png)
名前を設定、
LanguageをJapaneseに設定、
Skill typeをDialogに設定し
Create skillをクリック

![スクリーンショット 2021-08-28 21.21.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/f134b38c-9cc7-b8f1-a228-b25112799ba2.png)
作成したDialog Skillをクリック

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/dcdde19a-4ff4-2f66-ac24-2645040e7cad.png)
簡単のために構築済みIntentを利用します。
Content Catalogをクリック

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/bdb98492-1ea7-693f-3e83-6c78d315aab5.png)
一般カテゴリのインテントをAdd to skillで追加します

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/67fce3bf-c2aa-3107-3cec-040d3754c362.png)
Intentsタブで追加したIntentを確認できます。
また、Create　Intentで新しいIntentを作成できます。

![スクリーンショット 2021-08-28 21.29.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/913f2843-ff19-ff02-0d76-d028b7e9d7f7.png)
名前を設定し、５つ以上のサンプルを追加することで類似した入力を検知できるようになります。

![スクリーンショット 2021-08-28 21.31.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/c5be972c-0a8c-27d0-4100-85b3e235879c.png)
Dialogタブに移動し、Add nodeでいくつかノードを追加します。

![スクリーンショット 2021-08-28 21.32.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/506e5a96-4332-78f0-1ab2-f89df63c2fdb.png)

ノードを選択し、
Nameに名前
Enter conditionに認識するIntent（その他にも固有の語を認識するEntitiesや変数を認識するContextなどがある）
Assistant respondsに返答を設定する

これを作成したノード分行う。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/6e62a76c-e638-2e9c-78e0-41a9e7aac4ca.png)
設定が完了したら右上のTry itをクリック
![スクリーンショット 2021-08-28 21.40.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/d0cb23e1-9303-96cd-4964-bca08d240286.png)
テキストを入力することで動作をテストできます。

### 9.３.アプリの実装
#### UI側 

``` vuejs
<template>
    <div>
        <div>
            <BotLog :log='log' v-for="log in logs"/>
        </div>
        <div>
            <input type='text' v-model='sendData.text'>
            <input type='button' value='送信' @click='addLog'>
        </div>
    </div>
</template>
```
v-modelで入力が連動するようにしたテキスト入力欄とログを追加する関数を実行する送信ボタン
v-forでログ用コンポーネントを繰り返し表示する表示欄を作成します。

``` javascript
addLog(){
　　　　　　　　this.logs.push(Object.assign({},this.sendData)) //入力したデータをログに追加
    this.axios.post('/sendMsg', this.sendData) //APIにデータ送信
    .then((res) => {
        this.logs.push({
            speaker: 'bot',
            text: res.data.text
        }) //APIの結果をログに追加
    })
    this.sendData.text = '' //入力内容を初期化
}
```

#### Server側

ターミナルで`yarn add dotenv`を実行します。
これは環境変数を一時的に`.env`ファイルから呼び出せるようにするパッケージです。
APIキーや接続先URLなどの資格情報はコード内に書き込むのではなく、
他のファイルに分離しておくと後で接続先が変わった時などに便利です。
特に、kubernetesなどを使ったマイクロサービス的なシステムを構築する際は、
環境変数をkubernetesのyamlで管理可能なため、資格情報などを環境変数から呼び出すように作っておくことが推奨されています。

project一番上のディレクトリ(package.jsonがあるディレクトリ)に`.env`ファイルを作成します。
中身は

```
URL="<Watson AssistantのインスタンスURL>"
API_KEY="<作成したAssistantのAPIKEY>"
ASSISTANT_ID="<作成したAssistantのID>"
```
とします。
これらの情報は
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/cc354ab7-e7a6-639b-dd15-068b7148a7c0.png)
①左上の一覧をクリック
②３点ボタンをクリック
③Settingを選択　の順で表示することができます。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/8e245d61-4aa5-27a2-1aa5-555c519092b7.png)
ただし、Assistant URLはhttps://~ibm.comまでを使うようにしてください、これ以降を含めるとエラーになります。

`/srv/index.js`を開き、`import express from 'express';`の下に
`require('dotenv').config();`を追記します。

[Assistant API リファレンス](https://cloud.ibm.com/apidocs/assistant/assistant-v2?code=node#messagestateless)を開きます。
![スクリーンショット 2021-08-28 23.49.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/5e58ffe4-60b7-cbe5-522b-c291d17d0510.png)
Nodeタブを選択し、説明に従って
`npm install ibm-watson@^6.1.2`を実行します
![スクリーンショット 2021-08-28 23.51.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/64a7272a-a38b-14de-2afc-15ac19a0764f.png)
左の目次から`Send user input to assistant(stateless)`を選びます。
（Statelessでは直前の会話を保存しません、会話の結果を利用して次のノードに移動する場合などはStatefulを利用してください）

`/sendMsg`にPOSTメソッドを作成し、Example requestの内容を貼り付けます
その後
`'{apikey}'`を`process.env.API_KEY`
 `'{url}'`を`process.env.URL`
`'{assistant_id}'`を`process.env.ASSISTANT_ID`に書き換え

```javascript
input: {
    'message_type': 'text',
    'text': 'Hello',
}
```
の`'text'`を`req.body.text`に変更し、

```javascript
.then(res => {
    console.log(JSON.stringify(res.result, null, 2));
})
```
部分を呼び出し元への返信に書き換えます。

```javascript
.then(assistantResponse => {
     res.json({
          text: assistantResponse.result.output.generic[0].text
     });
})
```
完成形は下のようになります。

```javascript:/srv/index.js
app.post('/sendMsg', (req, res) =>{
    const AssistantV2 = require('ibm-watson/assistant/v2');
    const { IamAuthenticator } = require('ibm-watson/auth');

    const assistant = new AssistantV2({
      version: '2021-06-14',
      authenticator: new IamAuthenticator({
        apikey: process.env.API_KEY,
      }),
      serviceUrl: process.env.URL,
    });

    assistant
      .messageStateless({
        assistantId: process.env.ASSISTANT_ID,
        input: {
          'message_type': 'text',
          'text': req.body.text,
        }
      })
      .then(assistantResponse => {
        res.json({
          text: assistantResponse.result.output.generic[0].text
        });
      })
      .catch(err => {
        console.log(err);
      });
  })
```

完成形は図のようになります
![スクリーンショット 2021-08-29 0.12.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440309/d6fa2c25-a774-207e-490e-7f796185291a.png)

#### CroudFoundryへのアップロード用
`.cfignore`を開き、`.env`を追加します。

`manifest.yml`を開き、

```yml
   env:
     - URL: "<Watson AssistantのインスタンスURL>"
     - API_KEY: "<作成したAssistantのAPIKEY>"
     - ASSISTANT_ID: "<作成したAssistantのID>"
```
を追加します

設定は以上です。