その他

Node.jsで掲示板アプリのAPIを作成してみよう(掲示板関連API編)

その他
この記事は約12分で読めます。

implの岡本です。
掲示板アプリAPI作成の第四弾です。

今回は掲示板の新規作成、編集、削除を作成していきたいと思います。

ルーティングの作成

src/router/index.tsに下記を追記します。

# src/router/index.ts
import express from "express";
const router = express.Router();

router.use("", require("./routes/auth"));
router.use("", require("./routes/board")); //追記

module.exports = router;

src/router/routesディレクトリにboard.tsファイルを新しく作成します。

# src/router/routes/board.ts
import express from "express";
const router = express.Router();
const { BoardController } = require("../../api/controller/BoardController");
const {
  boardCreateRule,
  boardUpdateRule,
} = require("../../api/handler/rules/board.ts");
const { validateError } = require("../../api/handler/rules/validateError");

const boardContext = new BoardController();

router.get("/boards", boardContext.allBoard);
router.post("/board", boardCreateRule, validateError, boardContext.postBoard);
router.get("/board/:id", boardContext.showBoard);
router.put("/board/:id", boardUpdateRule, validateError, boardContext.putBoard);
router.delete("/board/:id", boardContext.deleteBoard);

module.exports = router;

コントローラーの作成

src/api/controller/BoardController.tsを新しく作成します。

# src/api/controller/BoardController.ts
import { Request, Response } from "express";
import {
  getBoards,
  createBoard,
  getBoard,
  updateBoard,
  destroyBoard,
} from "../model/Board";

export class BoardController {
  async allBoard(_req: Request, res: Response): Promise<void> {
    const boards = await getBoards();
    res.status(200).json({
      message: "board get all is success",
      boards,
    });
  }

  async postBoard(
    req: Request,
    res: Response
  ): Promise<void> {
    const { title, content, userId } = req.body;
    try {
      const board = await createBoard(title, content, userId);

      if (!board) throw new Error("this board does not create");

      res.status(201).json({
        message: "this board create is success",
        board,
      });
    } catch (error: any) {
      res.json({
        message: error.message,
      });
    }
  }

  async showBoard(
    req: Request,
    res: Response
  ): Promise<void> {
    try {
      const id = parseInt(req.params.id);

      const board = await getBoard(id);

      if (!board) throw new Error("this board does not get");

      res.status(200).json({
        message: "this board get is success",
        board,
      });
    } catch (error: any) {
      res.json({
        message: error.message,
      });
    }
  }

  async putBoard(
    req: Request,
    res: Response
  ): Promise<void> {
    const { title, content } = req.body;
    try {
      const id = parseInt(req.params.id);

      const board = await updateBoard(id, title, content);
      if (!board) throw new Error("this board does not update");

      res.status(201).json({
        message: "this board update is success",
        board,
      });
    } catch (error: any) {
      res.json({
        message: error.message,
      });
    }
  }

  async deleteBoard(
    req: Request,
    res: Response
  ): Promise<void> {
    try {
      const id = parseInt(req.params.id);

      const board = await destroyBoard(id);

      if (!board) throw new Error("this board does not delete");

      res.status(201).json({
        message: "this board delete is success",
      });
    } catch (error: any) {
      res.json({
        message: error.message,
      });
    }
  }
}

モデルの作成

src/api/model/Board.tsを新しく作成します。

# src/api/model/Board.ts
import { Board } from "@prisma/client";
import { prismaContext } from "../../lib/prismaContext";

export const getBoards = async () => {
  const board = await prismaContext.board.findMany({
    include: {
      user: {
        select: {
          name: true,
        },
      },
    },
  });
  return board;
};

export const createBoard = async (
  title: string,
  content: string,
  userId: number
): Promise<Board | null> => {
  const board = await prismaContext.board
    .create({
      data: {
        title,
        content,
        userId,
      },
    })
    .catch(() => {
      return null;
    });

  return board;
};

export const getBoard = async (existId: number): Promise<Board | null> => {
  const board = await prismaContext.board
    .findUniqueOrThrow({
      where: { id: existId },
      include: {
        user: {
          select: {
            name: true,
          },
        },
        comments: {
          include: {
            user: {
              select: {
                name: true,
              },
            },
          }
        }
      },
    })
    .catch(() => {
      return null;
    });

  return board;
};

export const updateBoard = async (
  existId: number,
  title: string,
  content: string,
): Promise<Board | null> => {
  const board = await prismaContext.board
    .update({
      where: { id: existId },
      data: { title, content },
    })
    .catch(() => {
      return null;
    });
  return board;
};

export const destroyBoard = async (existId: number): Promise<Board | null> => {
  const board = await prismaContext.board
    .delete({
      where: { id: existId },
    })
    .catch(() => {
      return null;
    });

  return board;
};

バリテーションの作成

src/api/handler/rules/board.tsを新規作成します。

# src/api/handler/rules/board.ts
import { check } from "express-validator";

export const boardCreateRule = [
  check("title")
    .not()
    .isEmpty()
    .withMessage("title is required")
    .isLength({ max: 255 })
    .withMessage("title mast be at largest 255 characters"),
  check("content")
    .isLength({ max: 255 })
    .withMessage("content mast be at largest 255 characters")
];

export const boardUpdateRule = [
  check("title")
    .not()
    .isEmpty()
    .withMessage("title is required")
    .isLength({ max: 255 })
    .withMessage("title mast be at largest 255 characters"),
  check("content")
    .isLength({ max: 255 })
    .withMessage("content mast be at largest 255 characters")
];

動作確認

前回同様Postmanを使用した場合の内容になります。

掲示板の新規作成の検証

userIdはデータベースに登録のあるユーザーのIDを使用してください。
URL: http://localhost:3000/api/board
HTTPメソッド: POST
BODY:

{
    "title": "CreateTitle01",	
    "content": "testContent01",	
    "userId": 1
}	

掲示板の更新の検証

userIdはデータベースに登録のあるユーザーのIDを使用してください。
URLのboard/1の1はデータベースにある掲示板のIDを使用してください。

URL: http://localhost:3000/api/board/1
HTTPメソッド: PUT
BODY:

{
    "title": "UpdateTitle01",	
    "content": "testContent01",	
    "userId": 1
}	


掲示板の詳細の検証

URL: http://localhost:3000/api/board/1
HTTPメソッド: GET
BODY: 不要です

掲示板の削除の検証

URL: http://localhost:3000/api/board/1
HTTPメソッド: DELETE
BODY: 不要です

次回はコメント関係のAPI作成を行います