【Nuxt.js】API(バックエンド)でMySQLからテーブル情報を取得しフロントエンドで表示させるアプリの作成


#1 はじめに

【アプリ作成の目的】
フロントエンド(Nuxt.js),バックエンド(express)を利用したアプリ作成を理解する。フロントエンドとサーバーエンドを分離したアプリとする。

【フロントエンドで行うこと】
・axiosを利用してバックエンド側(API)にリクエストを投げ、取得したデータを表示させる。
・ホームディレクトリは、「nuxt-scraping-app」とする。

【バックエンドで行うこと】
・事前にスクレイピングしてMySQLに保存したデータをjsonで返すAPIを作成する。
・ホームディレクトリは、「api-nuxt-puppeteer」とする。

【注意点】
※今回スクレイピング部分のコードに関しては、割愛させていただきます。
※スクレイピングの情報取得先はファッション系サイトであるfarfetchの商品を選択しました(sacaiのアイテム)。
※まだ理解が浅い為間違っている箇所はご指摘いただけると助かります！

【完成形】
![スクリーンショット 2020-12-24 13.18.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620533/dfd19f66-3291-c382-e37d-83079ea00abd.png)

#2 APIの作成(バックエンド)
サーバーサイドにExpressを利用する。
※Expressとは、Node.jsのフレームワーク。Rubyで言うところのRails。
こちらの説明がわかりやすかったです↓
[expressは一体何をしとるんじゃ・・・](https://qiita.com/ganariya/items/85e51e718e56e7d128b8)

【手順】

```ruby:nuxt-scraping-app
＄ npm install express # npmを利用
＄ yarn add express # yarnを利用
```
ホームディレクトリで上記のようにどちらかでexpressを導入する。
ちなみに、「npm install express --save」のように記載している記事がありますが、「--save」はnpmバージョン5.0.0からオプションを付けなくてもデフォルトでsaveされる為、必要ないようです。
[npm install時に「--save」オプションはいらない](https://qiita.com/havveFn/items/c5beda8572aa8c1e6be6)

今回npmコマンドを利用する為、package.jsonのdependenciesにexpressが追加されていることを確認する↓

```ruby:package.json
  "dependencies": {
    "@nuxtjs/axios": "^5.12.2",
    "core-js": "^3.6.5",
    "express": "^4.17.1", # New!
    "mysql": "^2.18.1",
    "mysql2": "^2.2.5",
    "nuxt": "^2.14.6",
    "sequelize": "^6.3.5"
  },
```

今回、APIを作成する為、apiディレクトリを作成し、index.jsを作成し以下のように記載。

```ruby:api/index.js
const express = require('express'); //expressを利用することを定義
const app = express(); # expressをappと定義

const mysql      = require('mysql'); //今回はMySQLを利用する
const connection = mysql.createConnection({　// 以下、各自のMySQLへの接続情報を書く
  host     : 'localhost',
  user     : 'root',
  password : '******',
  database : 'db_development'
});

app.get('/', function (req, res) {　// app.get...(expressの構文)、req=request。 res=response
  res.set({ 'Access-Control-Allow-Origin': '*' }); // この記載により、※1：CORSを許可する
  connection.query('select * from scrapings', function (error, results) { // scrapingsテーブルから全てのカラムを取得する
    if (error) throw error; // エラー処理
    res.send(results[0]); // results[0]により、一番目のデータを返答する
  });
});

app.listen(5000, function () { // port 5000をlistenする
  console.log('Example app listening on port 5000!'); // console.logによりファイル実行時にコンソールに文字表示させる
});

```

※1 CORS...オリジン間リソース共有。このコードを入れないとエラー発生してブラウザで見ることができません。こちらの記事が分かりやすかったです。難しい為私も絶賛勉強中です！
[・なんとなく CORS がわかる...はもう終わりにする。](https://qiita.com/att55/items/2154a8aad8bf1409db2b)
[・CORS(Cross-Origin Resource Sharing)]
(http://www.tohoho-web.com/ex/cors.html)


↓MySQLのカラム情報は以下の通りです。

```ruby:MySQL(Local)
mysql> describe scrapings;+--------------+--------------+------+-----+---------+----------------+| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int          | NO   | PRI | NULL    | auto_increment |
| imageUrl     | varchar(255) | YES  |     | NULL    |                |
| brandName    | varchar(255) | YES  |     | NULL    |                |
| itemName     | varchar(255) | YES  |     | NULL    |                |
| price        | int          | YES  |     | NULL    |                |
| material     | varchar(255) | YES  |     | NULL    |                |
| brandStyleId | varchar(255) | YES  |     | NULL    |                |
| createdAt    | datetime     | NO   |     | NULL    |                |
| updatedAt    | datetime     | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)
```

MySQLについて、Sequelizeと言うORM(*ORM...オブジェクトリレーションマッピング)を利用するとMySQL操作が容易になります。ここでは詳しく触れませんが、MySQLにターミナルからQUery操作しなくても、テーブルに改修を加えることができます。しかし、私を含め、初学者の方は直のSQL操作をで基礎的事項として覚えた方がよいと感じました。

Sequelizeについてはこちらが分かりやすかったです！
[Node.JSのSequelize ORM入門](https://qiita.com/markusveeyola/items/64875c9507d5fa32884e)

```ruby:/api
$ node index.js 
```

により起動させます。**注意として、index.jsを置いているディレクトリ(/api)で実行してください。ホームディレクトで実行するとエラーで実行できません。**

API(サーバーエンド)側は以上です。

#3 フロントエンドの作成(Nuxt.js)
CSSフレームワークとしてVuetifyを利用。モダンなフロントデザインにできるのでオススメです。create-nuxt-appでデフォルトでVuetify.jsを選択できるので、特に別途でinstallは必要はありません。

```ruby:desktop
$ create-nuxt-app api-nuxt-puppeteer
 Choose UI framework (Use arrow keys)
  None
  Ant Design Vue
  Bootstrap Vue
  Buefy
  Bulma
  Element
  Framevuerk
  iView
  Tachyons
  Tailwind CSS
  Vuetify.js # ←こちら！
```

同時に、「Choose Nuxt.js modules」でaxiosも選択しておきます(※axios...HTTP通信を簡単に行うことができるJavaScriptライブラリ。主にJSONの取得に利用されることが多い)。axiosについて詳しくはこちら↓
[axios の導入と簡単な使い方](https://qiita.com/ksh-fthr/items/2daaaf3a15c4c11956e9)

既存アプリにaxiosを導入する場合はこちら↓

```ruby:
$ npm install axios
```

Nuxtではpagesディレクトリ配下にファイルを置くと、自動的にルーティングされる
(例: pages/about.js...http://localhost:3000/about)

今回は特にルーティングは使用しない為、index.vueに書いていきます(フロントは簡素化しています)。

```ruby:pages/index.js
<template>
  <v-card class="mx-auto">
    <v-list-item>
      <div class="scraping">
        <h5>ID：{{ items.id }}</h5>
        <h5>商品画像URL：{{ items.imageUrl }}</h5>
        <h5>ブランド名：{{ items.brandName }}</h5>
        <h5>アイテム名：{{ items.itemName }}</h5>
        <h5>価格：￥{{ items.price }} (税込)</h5>
        <h5>素材：{{ items.material }}</h5>
        <h5>ブランドスタイルID：{{ items.brandStyleId }}</h5>
      </div>
    </v-list-item>
  </v-card>
</template>

<script>
export default {
  async asyncData({ $axios }) {
    const items = await $axios.$get("http://localhost:5000");
    return { items };
  },
};
</script>
```

```ruby:pages/index.js
<script>
export default {
  async asyncData({ $axios }) { 
    const items = await $axios.$get("http://localhost:5000");
    return { items };
  },
};
</script>
```
asyncDataで外部からデータを取得します。今回の場合は、http://localhost:5000
に表示しているMySQLから取得した情報(api側)をフロント側から表示させます。itemsとしてreturnします。

```ruby:pages/index.js
 <h5>ID：{{ items.id }}</h5>
```

このように、itemsとして返された情報を、例としてidカラムと指定することで、フロントに表示させます。


以上で、npm run dev, yarn devでローカルでサーバーを実行させると、最初のように表示できるはずです。