Web開発ログ | エンジニアに役立つ情報 | 開発の中での気づきを発信

高卒Devlog

TSLab【第5回 Express勉強会】POST/DELETE

thumbnail

こんにちは! RYOTAです!

当記事をご覧くださりありがとうございます!

定例になりましたTypeScript勉強会を開催したので実施ログを残していきます! 前回の続きとなるので気になる方は前回の内容も合わせてご覧くださいませ!

内容

前回もPUTのリファクタリングで時間を使ってしまったので今回はPOST/DELETEを一気に仕上げていきます。
バリデーションや処理自体はPUTの方がボリュームがあったのでPOST/DELETEはそこまで記述量が多くないと思います。
では早速内容にいきましょう。

POST Userの実装

POSTの処理フローとしては下記の通りになります。

  1. bodyのキーが一致しているかチェック
  2. name が文字列かチェック
  3. age が数値かチェック
  4. name が重複していないかチェック
  5. データを作成
  6. 結果をレスポンス

PUTと違いnameとageはどちらか欠けてもエラーを返すよう設計しました。
実際のコードは以下の通りです。
post_user.ts

import { Request, Response } from 'express'
import {
  PARAMETER_NOT_MAYCH,
  DUPLICATE_NAME,
  PARAMETER_INVALID,
} from '../../constants/error'
import { Handler } from '../../core/handler'
import { User } from '../../models/index'
import { IPostUserParams } from '../../types'
import CheckUtils from '../../utils/check'

export class PostUser {
  handler: Handler
  params: IPostUserParams

  constructor(req: Request, res: Response) {
    this.handler = new Handler(req, res)
    this.params = { ...req.params, ...req.body }
  }

  /**
   * メイン処理
   */
  async main() {
    const validParams = ['name', 'age']

    if (!CheckUtils.CheckMatchParams(this.params, validParams)) {
      return this.handler.error(PARAMETER_NOT_MAYCH)
    }

    if (
      typeof this.params.name !== 'string' ||
      typeof this.params.age !== 'number'
    ) {
      return this.handler.error(PARAMETER_INVALID)
    }

    const isDuplicateName = await this.checkDuplicateName()
    if (!isDuplicateName) return this.handler.error(DUPLICATE_NAME)

    const data = await this.createUser()

    return this.handler.json<number>(data)
  }

  /**
   * nameが一致するユーザーを取得
   */
  async checkDuplicateName(): Promise<boolean> {
    const response = await User.findAll({
      where: {
        name: this.params.name,
      },
    })

    return !response.length
  }

  /**
   * ユーザーを新規作成
   */
  async createUser(): Promise<number> {
    const response = await User.create({ ...this.params })

    return response.id
  }
}

PUTとパラメーターチェックの処理が異なるのでこちらは別途追加します。
utils/check.ts

  /**
   * パラメーターが一致しているかチェック
   */
  static CheckMatchParams(params: {}, validParams: string[]): boolean {
    return validParams.every((key) => Object.keys(params).includes(key))
  }

APIができたらコントローラー側で呼び出す処理を追加します。
router/users/Controller.ts

import { Router } from 'express'
import { GetUsers } from './users/get_users'
import { PutUser } from './users/put_user'
import { PostUser } from './users/post_user'

const router = Router()

router.get('/', (req, res, next) => {
  new GetUsers(req, res).main().catch(next)
})

router.put('/:id', (req, res, next) => {
  new PutUser(req, res).main().catch(next)
})

// ここから追加
router.post('/', (req, res, next) => {
  new PostUser(req, res).main().catch(next)
})
// ここまで追加

export default router


実装としてはこれだけです!
あとは実行して問題がなければ完了になります!

DELETE Userの実装

DELETEの処理フローとしては下記の通りになります。

  1. 対象のユーザーが存在するかチェック
  2. 対象のユーザーを削除
  3. 結果をレスポンス

処理自体はDELETEが一番シンプルですね。
実際のコードは以下の通りです。
users/delete_user.ts

import { Request, Response } from 'express'
import { NO_DATA_EXISTS } from '../../constants/error'
import { Handler } from '../../core/handler'
import { User } from '../../models/index'

export class DeleteUser {
  handler: Handler
  id: number

  constructor(req: Request, res: Response) {
    this.handler = new Handler(req, res)
    this.id = Number(req.params.id)
  }

  /**
   * メイン処理
   */
  async main() {
    const user = await User.findByPk(this.id)
    if (!user) return this.handler.error(NO_DATA_EXISTS)

    const data = await this.deleteUser(user)
    return this.handler.json<boolean>(data)
  }

  /**
   * ユーザーを削除
   */
  async deleteUser(deleteUser: User): Promise<boolean> {
    const response = await deleteUser.destroy()

    return Boolean(response)
  }
}

こちらもルーター側に追加したか完了です。
routes/users/Controller.ts

import { Router } from 'express'
import { GetUsers } from './users/get_users'
import { PutUser } from './users/put_user'
import { PostUser } from './users/post_user'
import { DeleteUser } from './users/delete_user'

const router = Router()

router.get('/', (req, res, next) => {
  new GetUsers(req, res).main().catch(next)
})

router.put('/:id', (req, res, next) => {
  new PutUser(req, res).main().catch(next)
})

router.post('/', (req, res, next) => {
  new PostUser(req, res).main().catch(next)
})

// ここから追加
router.delete('/:id', (req, res, next) => {
  new DeleteUser(req, res).main().catch(next)
})
// ここまで追加

export default router

さいごに

第一回の環境構築回から始まりやっとCLUDの基本的なAPIが出揃いました!
ここまででExpressの超基本的なことが出来るようになったので、あとは応用でアプリケーションが作成可能になったと思います。
次回はまた横道に逸れて、MongoDBでDB操作ができるよう構築を進めていこうと思います!