Nuxt.jsとmysqlを連携してデータを表示してみた

# はじめに
前から気になっていたNuxt.jsを触ってみました。これ使って何かやってみようと考えた結果、
mysqlと連携させてみることにしました。Nuxt.jsに関して入門的な情報は既にいろいろと存在するので、
ここでは、そのつなぎの部分にフォーカスして記載したいと思います。

# 内容
下記の項目に沿って記載します。

- Nuxt.jsについて
- Nuxt.jsのインストール
- データベース準備
- 必要なモジュール
- APIの実装
- フロントエンドの実装
- 結果
- おわりに

# Nuxt.jsについて
ご存知の方には恐縮ですが、Nuxt.jsはナクストと読むようであり、
Webアプリケーションを開発するのに必要なものが既にある程度整った状態で
スタートできるVue.jsベースのJavaScriptフレームワークです。
UIではVue.jsを使いますが、UI以外の機能についてもいろいろ組み込まれているようです。
フレームワークなので効率的にアプリケーションの開発ができるようですね。

# Nuxt.jsのインストール
早速、自分のPCにインストールしてみます。
事前にnpm と Node.jsがインストールされていることが前提です。

```
npx create-nuxt-app プロジェクト名
```

この形式でインストールするようなので、

```
npx create-nuxt-app prj
```
プロジェクト名をprjとして実行してみました。
いくつか聞かれるので、

- server framework を Express 
- Nuxt.js module をAxios
- rendering mode をUniversal (SSR)

として設定しました。
何度も繰り返し試した結果、上記の設定に落ち着きました。
Nuxt v2.10.2　がインストールされたようです。


次に、アプリを起動する必要があるので、

```
npm run dev
```

を打ち込むと、サーバーが起動します。
![nuxtserver.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287208/8d1b6431-6db7-257e-816a-acb78ffdeeaf.png)

```
npm run スクリプト名
```
ここで、上記の形式で入力すると、package.json（下記）で記述されているscripts内のスクリプト名
（この場合は"dev"）で定義されたコマンドが実行されます。

```json
{
  "name": "prj",
  "version": "1.0.0",
  "description": "My swell Nuxt.js project",
  "author": "**** ****",
  "private": true,
  "scripts": {
    "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
    "build": "nuxt build",
    "start": "cross-env NODE_ENV=production node server/index.js",
    "generate": "nuxt generate"
  },
  "dependencies": {
    "@nuxtjs/axios": "^5.3.6",
    "cross-env": "^5.2.0",
    "express": "^4.16.4",
    "fs": "0.0.1-security",
    "mysql": "^2.17.1",
    "net": "^1.0.2",
    "nuxt": "^2.0.0",
    "tls": "0.0.1"
  },
  "devDependencies": {
    "nodemon": "^1.18.9"
  }
}
```


下記URLをブラウザで表示すると、

```
http://localhost:3000
```
![nuxtinit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287208/6dc37799-c5be-1dc8-b8f3-5eb7153ad1c1.png)







こんな感じに初期表示されました。
Nuxt.jsのデフォルトポートは3000のようです。
インストールされたあとのディレクトリ構造は下記のようになってました。

```
prj----assets
    |--components
    |--layouts
    |--middleware
    |--node_modules
    |--pages
    |--plugins
    |--server
    |--static
    |--store
    |nuxt.config.js
    |package.json
```

調べたところ、最初に表示されたページは、

```
prj--
    |--pages
         |index.vue
```

pagesディレクトリ内にあるindex.vueに記載された内容でした。

```html
<template>
  <div class="container">
    <div>
      <logo />
      <h1 class="title">
        prj
      </h1>
      <h2 class="subtitle">
        My laudable Nuxt.js project
      </h2>
      <div class="links">
        <a
          href="https://nuxtjs.org/"
          target="_blank"
          class="button--green"
        >
          Documentation
        </a>
        <a
          href="https://github.com/nuxt/nuxt.js"
          target="_blank"
          class="button--grey"
        >
          GitHub
        </a>
      </div>
    </div>
  </div>
</template>

<script>
import Logo from '~/components/Logo.vue'

export default {
  components: {
    Logo
  }
}
</script>

<style>
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

.title {
  font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  display: block;
  font-weight: 300;
  font-size: 100px;
  color: #35495e;
  letter-spacing: 1px;
}

.subtitle {
  font-weight: 300;
  font-size: 42px;
  color: #526488;
  word-spacing: 5px;
  padding-bottom: 15px;
}

.links {
  padding-top: 15px;
}
</style>
```

ごちゃごちゃ書かれているので、余計な記述をバッサリ削除してコードを見やすくします。

```html
<template>
  <div class="container">
   あいうえお
  </div>
</template>

<script>
</script>

<style>
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}
</style>
```

表示は、下記のようになりました。

![nuxtinit2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287208/dd719146-aefd-9d2f-ee88-d30a20a79ca8.png)


ここで気づいたのが、このindex.vueファイルを更新した場合、
ブラウザで再描画しなくても（F5押さなくても）自動でブラウザに反映されることです。
index.vueファイルを更新するたびに、自動でコンパイルが走るようで、
それが終わり次第ブラウザの表示が変更されるようです。


# データベース準備
mysqlと連携させて何かしたいな？と考えたところ、
一番簡単なお試し内容として、DBに登録されているデータを取り出して、
それをブラウザに表示させてみるのがよさそうかなと思い、それを実装
してみることにしました。


なので、まずデータベースの準備をします。ローカル環境のmysqlにテスト用のデータベースを作成し
その中に都道府県情報のテーブルを作成しました。
データベース名：testdb
テーブル名：prefectures
![prefdb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287208/dffde015-e59d-ddcd-9ebc-be554e28bf40.png)
この情報を取り出してブラウザに表示させてみようと思います。


# 必要なモジュール

mysqlを使うには、どうやらmysql用のモジュールをインストールする必要が
あることがわかりましたので下記を実行します。

```
npm install --save mysql
```


# APIの実装
index.vueの中のscritpt要素の中に、データベースアクセスの為の記述をしても
うまくいかずエラーを解消することができなかったので、
別途APIを作成し、そこにアクセスすることでDBの内容をとってくる、
という方法にしました。

```
prj--
    |--server
         |api.js
```

serverディレクトの直下にapi.jsというファイルを作成し、
dbに接続してデータを取ってくるコードを記述します。

```javascript

const express = require('express')
const router = express.Router()
router.get('/prefectures', (req, res, next) => {
  const mysql = require('mysql');
  const connection = mysql.createConnection({
    host : 'localhost',
    user : 'testuser',
    database: 'testdb',
    password: 'testuser'
  });
  var ret=[];
  connection.connect();
  connection.query('SELECT * from prefectures;', function(error, row, fields){
    if (error) {
      console.log(error);
    } 
    var dat = [];
    for (var i = 0;i < row.length; i++) {
      dat.push({id: row[i].id, name: row[i].name});
    }
    ret = JSON.stringify(dat);
    res.header('Content-Type', 'application/json; charset=utf-8')
    res.send(ret)
  });
  connection.end();
})
module.exports = router
```

実はこれだけではだめなようで、同じディレクトリに存在するindex.jsというファイルを
一部編集しないといけないようです（★印の箇所）

```javascript
const express = require('express')
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
const app = express()

// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = process.env.NODE_ENV !== 'production'

//↓↓↓★この行の追加
const apiRouter = require('./api')
async function start () {
//↓↓↓★この行の追加
app.use('/api', apiRouter)

  // Init Nuxt.js
  const nuxt = new Nuxt(config)

  const { host, port } = nuxt.options.server

  // Build only in dev mode
  if (config.dev) {
    const builder = new Builder(nuxt)
    await builder.build()
  } else {
    await nuxt.ready()
  }

  // Give nuxt middleware to express
  app.use(nuxt.render)

  // Listen the server
  app.listen(port, host)
  consola.ready({
    message: `Server listening on http://${host}:${port}`,
    badge: true
  })
}
start()
```

下記でアクセスするとDBからのデータをJSON形式でとってこれるようになりました。

```
http://localhost:3000/api/prefectures
```
![nuxt_api.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287208/0f8d323e-d16e-f40b-ab55-2c40c9ca2e40.png)


参考サイト
https://dev.classmethod.jp/etc/node-js-module-mysq/
（他にもいくつか参考サイトがあったのですが忘れてしまった。。）

# フロントエンドの実装

axiosというライブラリを使ってhttp通信を行います。
Node.jsで動作するhttpクライアントであり、通信するためのAPIが提供されているので
これを利用します（Ajaxのようなものですね。多分）

上記でばっさり削除したindex.vueの中を下記のように変更します。
先ほどのAPIにアクセスして取ってきたデータをitemsの中に格納すると、
Vue.jsによってフロントエンドに反映されます。

```html
<template>
  <div class="container">
    <table border="1">
      <tbody>
      <tr>
        <th>ID</th>
        <th>都道府県名</th>
      </tr>
      <tr v-for="item in items" :key="item.id">
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
      </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: []
    }
  },
  mounted: function() {
    this.$axios
      .$get('/api/prefectures')
      .then(response => {
        this.items = response
      })
      .catch(error => {
        console.log(error)
      })
  }
}
</script>

<style>
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}
</style>
```



# 結果
表示は、下記のようになりました。

![nuxtresult.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287208/472eb4b2-dfbf-038e-84bf-c7dd3223bd96.png)




# おわりに
今回は、mysqlとの連携に注目しましたが、Nuxt.jsに関する知識が浅いこともあり、
もっといろんなこともできると思われますので、今後も引き続きいろいろ試してみたいと思います。
私はPHPを使っての作業が多いので、JavaScriptだけで当たり前のようにWebアプリケーションを
作れるようなったことに関心を寄せています。
試した内容は大したものではないですが、それでも途中いくつもの壁にぶち当たりました。
が、なんとか乗り越えました。
今後はよりスムーズに実装できるよう一層進化していくことと思います。