サーバ(Express)、データベース(mongoDB)間のやり取りをmongooseを使って実装してみる

バックエンド

<script>” title=”<script>

<script>

Webの概念としてクライアントから送られたリクエストをサーバが受け取り、サーバはデータベースとやり取りを行い、結果をクライアントへレスポンスとして返します。

今回はこの一連のやり取りのサーバ、データベース間の処理に注目して記事を書いていきます。

サーバはExpress、データベースはmongoDBを使って、処理自体はmongooseというライブラリを使って実装していきます。

メインアプリケーションファイル

まずはapp.jsです。

const express = require('express');
const app = express();
const tasksRouter = require('./routes/tasks');
const connectDB = require('./db/connect');
require('dotenv').config();
app.use(express.json());
app.use(express.static('./public'));

const port = 5001;

// ルーティング設計
app.use('/api/v1/tasks', tasksRouter);

//データベースと接続
const start = async () => {
  try {
    await connectDB(process.env.MONGO_URL);
    app.listen(port, () => {
      console.log(`サーバーがポート${port}で起動しました`);
    });
  } catch (error) {
    console.error('データベース接続エラー:', error);
  }
};

start();
  • ポート5001でサーバーを起動
  • /api/v1/tasksパスでタスク関連のAPIエンドポイントを設定
  • 環境変数からMongoDB接続URLを取得(process.env.MONGO_URL
  • express.json()でJSONデータの解析を有効化

データベース接続モジュール

次はdb > connect.jsです。このファイルではMongooseによるMongoDB接続機能を担っています。

const mongoose = require('mongoose');

const connectDB = (url) => {
  return mongoose
    .connect(url)
    .then(() => console.log('データベースと接続中...'))
    .catch((err) => console.log(err));
};

module.exports = connectDB;
  • mongoose.connect(url)でMongoDB Atlas/ローカルDBに接続
  • Promiseチェーンで接続状況をログ出力
  • app.jsでこの関数を呼び出してDB接続を確立

データモデル定義

次はmodels > Task.jsです。これはスキーマを定義するファイルです。

const mongoose = require('mongoose');

const TaskSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, 'タスク名を入力してください'],
    trim: true,
    maxlength: [20, 'タスク名は20文字以内で入力してください'],
  },
  completed: {
    type: Boolean,
    default: false,
  },
});

module.exports = mongoose.model('Task', TaskSchema);
  • バリデーション機能(必須項目、文字数制限)
  • デフォルト値の設定
  • MongoDB Collection “tasks”にマッピング

ルーティング定義

routes > tasks.jsです。このファイルはルーティング設定をしています。

const express = require('express');
const router = express.Router();
const {
  getAllTasks,
  createTask,
  getSingleTask,
  updateTask,
  deleteTask,
} = require('../controllers/tasks');

router.get('/', getAllTasks);

router.post('/', createTask);

router.get('/:id', getSingleTask);

router.patch('/:id', updateTask);

router.delete('/:id', deleteTask);

module.exports = router;
  • GET /api/v1/tasks – 全タスク取得
  • POST /api/v1/tasks – 新規タスク作成
  • GET /api/v1/tasks/:id – 特定タスク取得
  • PATCH /api/v1/tasks/:id – タスク更新
  • DELETE /api/v1/tasks/:id – タスク削除

ビジネスロジック

controllers > tasks.jsです。各APIエンドポイントの実際の処理を実装強いているファイルです。

const Task = require('../models/Tasks');

const getAllTasks = async (req, res) => {
  try {
    const allTasks = await Task.find({});
    res.status(200).json(allTasks);
  } catch (error) {
    res.status(500).json(error);
  }
};

const createTask = async (req, res) => {
  try {
    const createTask = await Task.create(req.body);
    res.status(200).json(createTask);
  } catch (error) {
    res.status(500).json(error);
  }
};

const getSingleTask = async (req, res) => {
  try {
    const getSingleTask = await Task.findOne({ _id: req.params.id });
    if (!getSingleTask) {
      return res.status(404).json(`ID:${req.params.id}のタスクは存在しません`);
    }
    res.status(200).json(getSingleTask);
  } catch (error) {
    res.status(500).json(error);
  }
};

const updateTask = async (req, res) => {
  try {
    const updateTask = await Task.findOneAndUpdate(
      { _id: req.params.id },
      req.body,
      { new: true }
    );
    if (!updateTask) {
      return res.status(404).json(`ID:${req.params.id}のタスクは存在しません`);
    }
    res.status(200).json(updateTask);
  } catch (error) {
    res.status(500).json(error);
  }
};

const deleteTask = async (req, res) => {
  try {
    const deleteTask = await Task.findOneAndDelete({ _id: req.params.id });
    if (!deleteTask) {
      return res.status(404).json(`ID:${req.params.id}のタスクは存在しません`);
    }
    res.status(200).json(deleteTask);
  } catch (error) {
    res.status(500).json(error);
  }
};

module.exports = {
  getAllTasks,
  createTask,
  getSingleTask,
  updateTask,
  deleteTask,
};
  • getAllTasks

Task.find({}) – 全タスクをMongoDBから取得

  • createTask

Task.create(req.body) – リクエストボディからタスク作成

  • getSingleTask

Task.findOne({ _id: req.params.id }) – ID指定でタスク取得

  • updateTask

Task.findOneAndUpdate() – ID指定でタスク更新

{ new: true }オプションで更新後のデータを返却

  • deleteTask

Task.findOneAndDelete() – ID指定でタスク削除

まとめ

アプリケーション起動

まずapp.jsがconnectDB()を呼び出し、connect.jsでMongoose経由でMongoDBと接続。接続成功後、Expressサーバがポート5001で起動し、クライアントからのHTTPリクエストを待機という流れになっています。

APIリクエスト処理

クライアントがHTTPリクエストを送信し、routes > tasks.jsファイルでルーティング。controllers > tasks.jsの対応する関数が実行され、Mongooseを通じてMongoDBを操作。結果をJSON形式でクライアントに返却という流れになっています。