76
70

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

FORKAdvent Calendar 2019

Day 24

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

Last updated at Posted at 2019-12-23

はじめに

前から気になっていた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

npm run スクリプト名

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

{
  "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

こんな感じに初期表示されました。
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に記載された内容でした。

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

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

<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

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

データベース準備

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

なので、まずデータベースの準備をします。ローカル環境のmysqlにテスト用のデータベースを作成し
その中に都道府県情報のテーブルを作成しました。
データベース名:testdb
テーブル名:prefectures
prefdb.png
この情報を取り出してブラウザに表示させてみようと思います。

必要なモジュール

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

npm install --save mysql

APIの実装

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

prj--
    |--server
         |api.js

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


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というファイルを
一部編集しないといけないようです(★印の箇所)

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://dev.classmethod.jp/etc/node-js-module-mysq/
(他にもいくつか参考サイトがあったのですが忘れてしまった。。)

フロントエンドの実装

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

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

<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

おわりに

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

76
70
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76
70

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?