React & Typescript & Node.js(express) & mysql でTodoを作成してみた(2)

# Node.js(express) , mysql の設定

今回は前回から続いて環境構築です。

今回tsを使うので型のインポートとモジュールシステムはrequireではなく、推奨の**import**を使います。

ではmysqlの設定からです。今までmysqlを使ったことはなかったので、最初はmysqlの導入になります。

```bash
mysql -u root -p
```
rootユーザーとして入ります。

mysqlサーバーのdb一覧は
```sql
show databases;
```
で見ることができます。

dbの作成は
```sql
CREATE DATABASE todo-app;
```
ここでのtodo-appは例です。上記の**show**を使えば、適切に作れているのかを確認できます。

テーブルの作成は
```
CREATE TABLE テーブル名 (
    カラム名1 データ型 [NOT NULL | NULL],
    カラム名2 データ型 [NOT NULL | NULL],
    カラム名3 データ型 [NOT NULL | NULL],
   ....
);
```
これが雛形で、今回は
```sql
CREATE TABLE todo_app.tasks 
    (id INT UNSIGNED AUTO_INCREMENT NOT NULL,
     user_id INT NOT NULL,
     content VARCHAR(255) NOT NULL,
     PRIMARY KEY (id) );
```
<font color="#ff0000">*id*　</font>　（テーブルの主キー（各レコードを一意に識別するフィールド）)
<font color="#ff0000">***user_id***　</font>（userの特定するためのキー)
<font color="#ff0000">***content***　</font>(userの送った情報)
<font color="#ff0000">***PRIMARY KEY***　</font>(idフィールドがこのテーブルの主キー（PRIMARY KEY）であることを示しています。主キーはテーブル内で一意の識別子として使用され、重複することは許さない)

<br/>

- **INT** : idは整数型（INT）であり、最大で約4億以上のユニークな値を持つことができます（UNSIGNED指定時）。
- **UNSIGNED** : 符号なし整数を指定します。つまり、負の値を許可せず、0以上の整数のみを格納します。通常、IDとして使用するカラムはUNSIGNEDにして負の値が入らないようにします。
- **AUTO_INCREMENT** : この指定により、idフィールドは新しいレコードが挿入されるたびに自動的に1ずつ増加します。これにより、各レコードが一意のIDを持つことが保証されます。
- **NOT NULL** : このフィールドは必ず値を持つ必要があり、NULLは許可されません。IDは常に値を持つべきなので、この指定がされています。
- **VARCHAR(255)** : contentは可変長文字列（VARCHAR）で、最大255文字までの文字列を格納できます。

## expressを用いた設定（サーバー）

まずはnode.jsで使えるように
```ts
import mysql from "mysql2";
```
ここではNode.js 用の人気のあるオープンソース ドライバーであるmysql2をimportしておきます

server用ファイル内で接続設定をします。
```ts
// MySQLの接続設定
const db = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'your_password', // 自分のMySQL root パスワード
    database: 'your_database_name'// 作成したデータベース名
});
```

またdb接続には正しくエラー処理を行わないといけないため、
```ts
//databaseのコネクション処理
db.connect((err) => {
    if(err) {
        console.log("error connecting : " , err.stack);
        return;
    }
    console.log("success!");
});
```
正しく接続できているかを確認します。

### 基本的なAPIエンドポイントの実装
```ts
app.get("/todo" , (req : Request, res : Response) => {
    const query = 'SELECT *FROM tasks';
    db.query(query , (err : mysql.QueryError | null , result : mysql.QueryResult) => {
        if(err){
            console.error("error getting tasks from databases" , err);
            return res.status(500).send({ message: 'Failed to fetch tasks' });
        } else {
            res.status(200).send(result);
        }
    })
});
```
データベースからデータを取ってくる処理は
```sql
SELECT  *FROM  テーブル名;
```
で実装できます。

```ts
pp.post("/todo" , (req : Request , res : Response) => {
    //分割代入を行う
    const { todo } = req.body;
    //ランダムにidを生成
    const id = Math.random().toString(36);
    const newTodo : todoHold = {id , content : todo};
    //データベースに登録する処理
    const query = "INSERT INTO tasks (user_id , content) values (?, ?)"; 
    db.query(query , [todo] , (err , result) => {
        if(err){
            console.error("Error saving databases : tasks" , err);
            return res.status(500).send({message : "failed to save data"});
        }
        res.status(201).send({ message: "Task added!", taskId: result});
    });
})
```
ここでは実際にフロントから渡された情報をdbに登録しています。
dbに登録する手順としてinsertがあります。

```
INSERT INTO テーブル名 
        (カラム名1, カラム名2, カラム名3, ...) 
    VALUES 
        (値1, 値2, 値3, ...);
```

インジェクション対策として、？プレイスホルダーを用いて、配列として扱っています。

このようにして無事、フロントからの情報を正しくdbに格納するような処理ができました。

<br>
最後にdbの確認をします
dbのカラムを確認したいので、

```sql
DESCRIBE tasks;
```

tasksテーブル内の全データを確認するには

```sql
SELECT * FROM tasks;
```
指定をしたければ、
```sql
SELECT id, content FROM tasks;
```

```
mysql> SELECT * FROM tasks;
+----+---------+-------------------+
| id | user_id | content           |
+----+---------+-------------------+
|  1 |       1 | int main void     |
|  2 |       1 | test1             |
|  3 |       1 | todo-appの作成    |
+----+---------+-------------------+
```

フロントからの情報を正しく受け取ってdbに登録できました！
<hr>

以下参考です

https://mysql.sql55.com/sql/mysql-create-table.php

https://qiita.com/Yasushi-Mo/items/50a7f6f7e0563c0a2592