Next.jsのapiでMySQL実行。クエリログの書き出しも

まず、インストールするライブラリです。
<ol>
<li>npm install serverless-mysql（必須）
→MySQL実行用</li>
<li>npm i sql-template-strings（ほぼ必須）
→MySQLのセキュリティ用（インジェクション防止）</li>
<li>npm install date-utils（あれば良い）
→ただ日付を簡単に取得したいだけ（クエリログとMySQL内のtimestamp用）</li>
</ol>

Next.jsの/pages/api内のエンドポイントを呼び出して、その中でMySQLを実行します。

Next.jsのapi領域は、Node.js環境なので、
今回使用する<a href="https://www.npmjs.com/package/serverless-mysql" target="_blank">serverless-mysql</a>以外にも、mysqlのライブラリがいくつかあり、
<a href="https://www.w3schools.com/nodejs/nodejs_mysql.asp" target="_blank">Node.js MySQL</a>なども、実行することができました。

今回は、serverless-mysqlの使います。

<h3>完成系</h3>
/lib/mysql.jsを作成

```
const mysql = require('serverless-mysql'); //エスケープ
require('date-utils'); //日時簡単取得


const db = mysql({
    config: {
        host: process.env.MYSQL_HOST,
        database: process.env.MYSQL_DATABASE,
        user: process.env.MYSQL_USER,
        password: process.env.MYSQL_PASSWORD
    }
})

//クエリログ書き出し
const queryLogWrite = (query, values) => {
    const fs = require("fs");　//ファイル書き出しモジュール
    let now = new Date();
    let excuteQuery = '\n' + now.toFormat('YYYY/MM/DD DDD HH:MI:SS') + query;
    values.forEach(data => {
        excuteQuery = excuteQuery.replace('?', data)
    })
    //書き込み
    fs.appendFile("log/query.log", excuteQuery, (err) => {
        if (err) throw err;
        //正常処理
    });
}

exports.query = async SQL => {
    try {
        //ログ書き出し
        queryLogWrite(SQL.query, SQL.values);

        const results = await db.query(SQL)
        await db.end()
        return results
    } catch (error) {
        return { error }
    }
}
```

<h4>ポイント</h4>

1.

```
//ログ書き出し
queryLogWrite(SQL.query, SQL.values);

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

values.forEach(data => {
    excuteQuery = excuteQuery.replace('?', data)
})
```
の部分は、
SQL.query：バインドパラメータが「?」状態のSQL文
SQL.values：バインドパラメータの配列
となっているので、
SQL.valuesをループで回してSQL文の「?」をリプレースして完全なクエリログを作成しています。


2.「process.env.」を使用しているので、Next.jsのドキュメントを見ながら、.env.local等のファイルを作成してください。（.gitignoreのファイル設定に気をつけて）

3.require("fs")は、Node.jsが持っている機能で、これを使ってquery.logファイルを書き出す＆追記します。
fs.appendFile
とすると、指定したファイルの最下行に、追加したいテキストを追記することができます。

4.

```
let now = new Date();
let excuteQuery = '\n' + now.toFormat('YYYY/MM/DD DDD HH:MI:SS') + query;
```
は、インストールした、date-utilsの機能で、js本来のgetfullyear等の年月日日時の取得をフォーマット指定で省略することができます。
今回は、クエリログ書き出し時のログ出力時間として使っています。


このファイルを、/pages/api内の別ファイルから呼び出して使用します。
今回は、/pages/api/login.tsというログイン用のエンドポイントから呼び出します。
（typescriptの書き方になっています。）

```

import type { NextApiRequest, NextApiResponse } from 'next'
const db = require('../../lib/mysql')
const escape = require('sql-template-strings')

type PostData = {
    email: string;
    password: string;
}

type QueryResult = {
    loginResult: boolean
}


export default async (req: NextApiRequest, res: NextApiResponse<QueryResult>) => {
    const postData: PostData = req.body;
    const queryResult = await db.query(escape`
    SELECT
        COUNT (USER_ID) AS count
    FROM
        USERLIST
    WHERE
        EMAIL = ${postData.email}
        AND PASSWORD = ${postData.password}
    `)

    res.status(200).json({ loginResult: 0 < queryResult[0].count ? true : false });
}

```


<h4>ポイント</h4>

1.ここは、../../lib/mysqlで実行するSQLを作成する役目です。
見ての通り、emailとpasswordでログイン認証を行なっています。
${postData.email}という、jsのヒアドキュメント内でjsの文字列を出力する書き方をしていますが、ヒアドキュメント開始直前に「escape」とあるのが、インストールしたsql-template-stringsで、
これにより、SQLインジェクションを防げるそうです。

 const queryResult = await db.query(escape` [SQL文] `)

が１セットとして見れば良いかと思います。
<hr>
以上の内容で、
MySQLのUSERLISTテーブル内から、email,passwordで認証を行なって、
当てはまるレコードが１件でもあればtrueを返し、
同時に上記のクエリログを/logs/query.logに書きだす処理を作成できました。

パスワードのハッシュ化、try,catch等、追加で書くとさらに良くなると思います。


※今回のクエリログは、localhost開発時には便利ですが、
実際に本番デプロイした後に（例えばvercelデプロイ）ログファイルを見れるか怪しいので、あくまで開発のお供として考えてください。
あと、logフォルダも.gitignoreに入れた方が良いかと思います。

以上です。