はじめに
Node.js+MySQL+Dockerを使用したAPIの作成をしていきます。
記事を書くにあたり、trelloクローンアプリの作成を最終目標としています。
その過程で、バックエンド構築の際に今回の記事の内容で作成してみました。
作成にあたり主に下記の記事を参考にしております。
【Docker】DockerにMySQL環境を構築する(M1 Mac 対応)
https://midorigame-jo.com/docker-mysql/
DockerでMySQL・Node.jsコンテナを用いたToDoリストアプリを作成する
https://qiita.com/niisan1ban/items/f70eb0ed891568f71f9b
次世代の Node.js ORM 、Prisma をサクッと入門する
https://zenn.dev/pyhrinezumi/articles/431be604f9ad50
【Web API】Talend API Testerを使ってみた
https://www.isoroot.jp/blog/4241/
環境
MacBookAir m1
VSCode
Node.js ver 18
MySQL ver 8.0.33
TypeScript
Prisma
Docker
1.環境構築
はじめに、docker-composeを作成します。
内容は下記の設定としております。
services:
db:
image: mysql:8.0.33
#Macbook m1を使用しているためplantformを指定
platform: linux/amd64
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: ユーザ名
MYSQL_PASSWORD: パスワード
MYSQL_DATABASE: trello
TZ: "Asia/Tokyo"
volumes:
- db-data:/var/lib/mysql
ports:
- 3307:3306
backend:
image: node:18-slim
volumes:
- ./backend:/usr/src/app
working_dir: /usr/src/app
command: bash -c "npm install && npm start"
ports:
- 3000:3000
depends_on:
- db
#URLはlocalhostではなく、docker-composeで指定しているservicesのdbを指定
environment:
DATABASE_URL: mysql://ユーザー名:パスワード@db:3306/trello
volumes:
db-data:
手間を省くため、docker-compose上でDBアクセス用のユーザの払い出しとデータベースの設定をしました。
それに伴いURLも変更しております。
使用している環境により設定する内容が変わるため、詳細は公式リファレンスを確認するようにしてください。
筆者はMacBookM1だったため、環境構築に苦労しました、、、
上記をプロジェクトのルートフォルダへ配置し、ターミナルで下記コマンドを実行します。
docker-compose up -d
これにより、MysqlとNode.jsの環境構築が完了しました。
2.テーブル設定
では、次にデータベースのテーブル設定を行います。
今回は、Prismaを使用してマイグレーションを行います。
Node.jsのORMはいくつかありますが、TypeScriptと親和性があり、使用しやすいイメージをがあったため、今回採用してみました。
ディレクトリをbackendフォルダに移動し、下記コマンドを順番に実行します。
npm init -y
npm install prisma --save-dev
npx prisma init --datasource-provider mysql
実行後、自動的にbackendフォルダ直下に.envファイルとPrismaフォルダとschema.prismaが作成されます。
ここでテーブル、カラム設定を行うことができます。
今回は下記のように設定を行います。
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model Boards {
id Int @id @default(autoincrement())
name String
board_order Int
}
.envファイルには、マイグレーション用のURLが記述してあります。
Dockerの環境に合わせ、下記のように設定しております。
DATABASE_URL="mysql://root:root@0.0.0.0:3307/trello"
localhostではなく、0.0.0.0を設定しています。
ポートはDocker-composeで設定した値です。
設定完了後、ターミナルでbackend下で下記コマンドを入力します。
npx prisma migrate dev --name init
完了すると、テーブルとカラムの設定が自動で行われます。
Dcoker DeskTopで確認してみましょう。
以上でデータベースの設定が完了です。
3.Node.jsでAPI構築
Node.jsのexpressを使用してAPIの作成をしていきます。
データベースの接続は本来であればPrismaをそのまま使用していきたいですが、MacBookM1でDockr上のMysqlをlinux/amd64で起動しているとエラーが出てしまい、うまく解消ができませんでした。
そのためmysql2を使用していきます。
まず、下記コマンドを実行していきます。
npm install express
npm install --save-dev typescript ts-node @types/node @types/express
npm install -D nodemon
npm install --save doting
npm install --save mysql2
npm install cors --save
次にtsconfig.jsonを作成し、下記内容とします。
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"sourceMap": true,
"outDir": "dist",
"lib": ["esnext"],
}
}
package.jsonに下記内容を修正、追加します。
//修正
"main": "server.ts"
//追加
"scripts": {
"start": "nodemon server.ts",
}
backend直下にserver.tsを作成します。
このファイルでAPIのサーバーの設定を行います。
import express, { response } from 'express';
import { BoardsController } from './controllers/boardsController';
import cors from 'cors'
require('dotenv').config();
const app: express.Express = express();
const port = 3000;
const boardsController = new BoardsController();
app.use(express.json());
app.use(cors());
app.listen(port,() => {
console.log("起動"+ port);
})
app.get("/",(request:express.Request,response:express.Response) => {
response.send("HTTPリクエスト確認");
})
app.get("/boards",boardsController.getAllBoards);
app.get("/boards/:id",boardsController.getBoardById);
app.post("/boards",boardsController.createBoard);
app.put("/boards/:id",boardsController.updateBoard);
app.delete("/boards/:id",boardsController.deleteBoard);
app.use((error:any,request:express.Request,response:express.Response, next:express.NextFunction) => {
console.error(error);
response.status(500).send("エラーが発生しました。");
});
backend直下にcontrollersフォルダを作成し、
boardsController.tsを作成します。
ここで、HTTPリクエストの処理を行うメソッドを定義していきます。
import express from 'express';
import { BoardsModel } from '../models/boardsModel';
const boardsModel = new BoardsModel();
export class BoardsController {
async getAllBoards(request:express.Request,response:express.Response, next:express.NextFunction) {
try {
const rows = await boardsModel.getAllBoards();
response.json(rows);
} catch (error:any) {
next(error);
}
}
async getBoardById(request:express.Request,response:express.Response, next:express.NextFunction){
const boardId = request.params.id;
try {
const rows = await boardsModel.getBoardById(boardId);
response.json(rows);
} catch (error:any) {
next(error);
}
}
async createBoard(request:express.Request,response:express.Response, next:express.NextFunction) {
const {name, board_order } = request.body;
try {
const result = await boardsModel.createBoard(name,board_order);
response.json(result);
} catch (error:any) {
next(error);
}
}
async updateBoard(request:express.Request,response:express.Response, next:express.NextFunction) {
const {id} = request.params;
const {name, board_order } = request.body;
try {
const result = await boardsModel.updateBoard(id,name,board_order);
response.json(result);
} catch (error:any) {
next(error);
}
}
async deleteBoard(request:express.Request,response:express.Response, next:express.NextFunction) {
const {id} = request.params;
try {
const result = await boardsModel.daleteBoard(id);
response.json(result);
} catch (error:any) {
next(error);
}
}
}
backend直下にmodelsフォルダを作成し、
boardsModels.tsを作成します。
ここでは、データベースにおけるCRUD処理を記述します。
import mysql from 'mysql2/promise';
require('dotenv').config();
const dbConnect = mysql.createPool({
host : process.env.DB_HOST,
user : process.env.DB_USER,
password : process.env.DB_PASSWORD,
database : process.env.DB_NAME,
connectTimeout: 100,
});
export class BoardsModel {
async getAllBoards() {
const [rows] = await dbConnect.execute("select * from Boards order by board_order ");
return rows;
}
async getBoardById(id:string) {
const [rows] = await dbConnect.execute("select * from Boards where id = ? ",[id]);
return rows;
}
async createBoard(name:string,board_order:number){
const [result] = await dbConnect.execute("insert into Boards set name = ?,board_order = ? ",[name, board_order]);
return result;
}
async updateBoard(id:string,name:string,board_order:number){
const [result] = await dbConnect.execute("update Boards set name = ?, board_order = ? where id = ?", [name, board_order, id]);
return result;
}
async daleteBoard(id:string) {
const [result] = await dbConnect.execute("delete from Boards where id = ?", [id]);
return result;
}
}
以上で、Node.jsの設定が完了です。
これで、API機能の完成です。
この状態で、「http://localhost:3000/」へアクセスすると
app.get("/")のレスポンスで設定していたsend()の内容が返却されます。
4.APIに対するHTTPリクエストの確認
APIの動作確認として、今回はchromeの拡張機能であるTalend API Testerを使用してみました。
Talend Cloud API Tester
https://help.talend.com/r/ja-JP/Cloud/api-tester-user-guide
①Getリクエスト
画面上部のタブから「リクエスト」を選択します。
メソッドから「GET」を選択します。
server.tsにて設定したURL「localhost」(http://localhost:3000/boards)
を指定し、送信を押下します。
画面下部にリクエストのレスポンス結果が表示されます。
先ほど追加した2つのデータがJSON形式で返却されることが確認できました。
②Postリクエスト
次に、POSTリクエストでデータを追加してみましょう。
メソッドから「POST」を選択します。
ボディに追加用のデータをJSON形式で記述し、送信を押下します。
再び、Getリクエストを送信してデータを確認してみると、Postリクエストで送信したデータが追加されていることが確認できます。
③Putリクエスト
今度は、先ほど追加したデータを更新してみましょう。
メソッドから「PUT」を選択し、URLに更新したいデータのidを指定し、送信を押下します。
下記のレスポンスが返却されたので、再度Getリクエストを送信し、対象のデータが更新されたか確認してみましょう。
先ほどPutリクエストで送信した内容で更新されたことが確認できます。
④Deleteリクエスト
最後にDeleteリクエストでデータを削除してみましょう。
メソッから「DELETE」を選択し、URLに削除したいデータのidを指定し、送信を押下します。
Getリクエストで削除されたかどうか確認してみましょう。
無事削除が正常に処理されていました。
以上で、実装したHTTPリクエストが全て正常に処理されていることが確認できました。
これにて、Node.js、Mysql、Dockerを使用したAPIの完成です。
最後に
初めてNode.jsやDockerを使用したAPI構築を行いましたが、環境構築でかなり手間取ってしまいました。
しかし、一から作り上げることで仕様を学ぶいい機会となりました。
この調子で最終目標であるtrelloのクローンアプリ完成を目指していきます。
最後まで記事を読んでいただきありがとうございました。