0
0

More than 5 years have passed since last update.

配列を仮想DBとした掲示板の作成(5/5):DELETEリクエスト編

Posted at

GitHub

前提条件

配列を仮想DBとした掲示板APIサーバの作成(1/5):はじめに・環境構築・DB、コメントモデルの作成

配列を仮想DBとした掲示板の作成(2/5):GETリクエスト・サーバ起動編

配列を仮想DBとした掲示板の作成(3/5):POSTリクエスト編

配列を仮想DBとした掲示板の作成(4/5):PUTリクエスト編

実装する機能

「DELETE/api/comment/:id」リクエストを送ると、id値に紐づいたComment1件を削除して、削除したComment1件がレスポンス値として返ってくる

この記事のまとめ

  • 指定したidと合致したcomment1件を削除して、そのコメントを返り値とするメソッドを作成した
  • DELETEリクエストを送った時のメソッドを作成した
  • メソッド名の変更を行なった
  • POSTMANでDELETEリクエスト時の動きを確認した

指定したid値と合致したcomment1件を削除して、削除したコメント1件を返すメソッドの作成(deleteComment()

deleteComment: ({ id }) => {
  if (typeof id !== 'number' || id < 1) {
    throw new Error(
      'idに適切でない値が入っています、1以上の数字を入れてください'
    );
  }

  const target = comments.findIndex(comment => id === comment.id);
  if (target === -1) {
    throw new Error('idと合致するCommentが見つかりません');
  }
  const deletedComment = comments.splice(target, 1)[0];

  return deletedComment;
},
  • id値に適切でないプロパティ値が入っている
  • id値と合致するcommentが見つからない

上記の場合はエラーを返し、適切な値が入っている場合のみメソッドが成功するように設計しました。

また、idのプロパティ値と配列のインデックス値は同一ではないので、配列内からid値と合致する要素を探す必要があります、そこでArray.prototype.findIndex()を使用します。

const target = comments.findIndex(comment => id === comment.id);

アロー関数の特徴である、文の戻り値を返すだけならブロックとreturnを省略した書き方をしています。
これで、id値と合致するコメントを配列内から探すことができます。

そして、コメントを一件削除して、そのコメントを返す必要があります。

const deletedComment = comments.splice(target, 1)[0];

return deletedComment;

Array.prototype.splice()は破壊的なメソッドです、第一引数に先ほど会得したtarget、第二引数で削除したい配列の数1を入れることで、id値と合致するコメント1件がcomments配列から削除されます。

ここで、splice()の末尾に[0]をつけてますが、これをつけることで、配列ではなく1件のデータとして要素を返すことができます。

詳しい説明はこちらで記事にしてます。
【Javascript】splice()の末尾に[0]をつけ取り除かれた要素1つをデータで返す - じんのアウトプット日記(だいたい毎日更新)

それでは、実際にうまく動作するかテストします。

deleteComment()のテスト

テスト内容

  1. Comment.deleteCommentはメソッドである
  2. idの引数に不正な値が入っていた場合、エラーが返る
  3. idの引数と合致するCommentがない場合、エラーが返る
  4. 適切なデータを送った場合、idと合致するComment1件が返ってくる
  5. 4.と同時に、idと合致するComment1件が配列から削除される。

この5点を確認します。

deleteComment.test.js
const assert = require('power-assert');
const Comment = require('../../models/Comment');

describe('Comment.deleteCommentのテスト', () => {
  // 以下にテストコードを記述していきます
});

1.Comment.deleteCommentはメソッドである

it('Comment.deleteCommentはメソッドである', () => {
  assert.strictEqual(typeof Comment.deleteComment, 'function');
});

typeof演算子で、Comment.deleteCommentがメソッドであるかどうかテストします。

2.idの引数に不正な値が入っていた場合、エラーが返る

it('idの引数に不正な値が入っていた場合、エラーが返る', () => {
  const invalidIdList = [
    { id: 0 },
    { id: -1 },
    { id: null },
    { id: {} },
    { id: [] },
    { id: '1' },
  ];

  invalidIdList.forEach(id => {
    try {
      Comment.deleteComment(id);
      assert.fail();
    } catch (error) {
      assert.strictEqual(
        error.message,
        'idに適切でない値が入っています、1以上の数字を入れてください'
      );
    }
  });
});

invalidIdList配列に思いつく限りの適切でない値を入れ、forEachで各値ごとにdeleteCommentを実行します。メソッドがエラーになるようであればcatchの方でエラーメッセージと比較します。 1つでも成功した場合はassert.fail()によりエラーで終了、失敗となります。

3.idの引数と合致するCommentがない場合、エラーが返る

it('idのプロパティ値と合致するCommentがない場合、エラーが返る', () => {
  const invalidId = { id: 999999999 };

  try {
    Comment.deleteComment(invalidId);
    assert.fail();
  } catch (error) {
    assert.strictEqual(error.message, 'idと合致するCommentが見つかりません');
  }
});

invalidIdに現在配列には入っていないid値を入れ、deleteCommentを実行します。メソッドがエラーになるようであればcatchの方でエラーメッセージと比較します。成功した場合はassert.fail()によりエラーで終了、失敗となります。

4.適切なデータを送った場合、idと合致するComment1件が返ってくる

  it('適切なid値を送った場合、idと合致するComment一件が返される', () => {
    const validId = { id: 1 };

    const deletedComment = Comment.deleteComment(validId);
    assert.deepEqual(deletedComment, {
      id: validId.id,
      username: deletedComment.username,
      body: deletedComment.body,
      createdAt: deletedComment.createdAt,
      updatedAt: deletedComment.updatedAt,
    });
  });

idに適切な値が入っていた場合は、deleteCommentが実行した時に、返ってくる要素の各プロパティ値には適切にデータが入っているかassert.deepEqualで確認します。

5.4.と同時に、idと合致するComment1件が配列から削除される。

it('適切なid値を送った場合、idと合致するComment一件が配列から削除される', () => {
  const oldComments = Comment.findAll();
  const validId = { id: 2 };

  Comment.deleteComment(validId);

  const currentComments = Comment.findAll();

  assert.equal(oldComments.length, currentComments.length + 1);
});

idに適切な値が入っていた場合は、deleteComment実行後、配列から要素が一件削除されているかテストします。

各テストが成功したら、次はAPIからDELETEリクエストをした時に、deleteCommentが実行するようにしていきます。

「DELETE/api/comment/:id」リクエストを送ると、id値と合致したcomment1件を削除して、削除したcomment1件がレスポンス値として返ってくるメソッドの作成(deleteComment())

comment.js(controller)
deleteComment: (req, res) => {
  try {
    const parsedId = parseInt(req.params.id, 10);

    const removeComment = Comment.removeComment({
      id: parsedId
    });

    res.status(200).json(removeComment);
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
}
comment.js(router)
router
  .route('/:id')
  .put(controller.putComment)
  .delete(controller.deleteComment);

今回もPUTリクエストと同じくルートパラメータを使用します。ルートパラメータで得た値を数値に変換し、removeCommentのid値に代入します。
と、その前に突然現れたremoveCommentとはなんでしょうか?

メソッド名の変更

今回DELETEリクエスト時に実行されるdeleteCommentと、指定したid値と合致したComment1件を削除して、削除したコメント1件を返すメソッドにて、modelsで作成したdeleteCommentの名前が被ってしまいましたので、 modelsの方をremoveCommentと改名しました。

deleteComment()のテスト

test/app/apiディレクトリにdeleteComment.test.jsファイルを新たに作成し、そちらでテストを行なっていきます。

deleteComment.test.js
const assert = require('power-assert');
const requestHelper = require('../../../helper/requestHelper');

const getComments = async () => {
  const response = await requestHelper.request({
    method: 'get',
    endPoint: '/api/comments',
    statusCode: 200,
  });
  return response.body;
};

const deleteComment = async (id, code) => {
  const response = await requestHelper.request({
    method: 'delete',
    endPoint: `/api/comments/${id}`,
    statusCode: code,
  });
  return response;
};

describe('TEST 「DELETE api/comments/:id」', () => {
  // 以下にテストコードを記述していきます
});

テスト内容

  1. 適切でないidを送ると400エラーが返る
  2. 送られたidとひもづくCommentがない場合、400エラーが返る
  3. 適切なデータを送った場合、idとひもづくCommentがレスポンス値として返ってくる。
  4. 3.と同時に、配列内にあったidとひもづくCommentは配列から削除される。

この4点を確認するテストコードを記述していきます。

1.適切でないidを送ると400エラーが返る

it('適切でないid値を送るとエラーが返る', async () => {
  const response = await deleteComment(0, 400);

  assert.deepStrictEqual(response.body, {
    message: 'idに適切でない値が入っています、1以上の数字を入れてください',
  });
});

id値に0(適切でない数値)を入れると、ステータスコードは400、そしてエラーメッセージが返ってくることを確認します。

2.送られたidとひもづくCommentがない場合、400エラーが返る

it('idの値と合致するCommentがない場合エラーが返る', async () => {
  const response = await deleteComment(9999999, 400);

  assert.deepStrictEqual(response.body, {
    message: 'idと合致するCommentが見つかりません',
  });
});

現在配列に入っているcommentのidのどれにも合致しない数字をidに入れると、ステータスコードは400、そしてエラーメッセージが返ってくることを確認します。

3.適切なデータを送った場合、idとひもづくcomment1件がレスポンス値として返ってくる。
4.3.と同時に、配列内にあったidとひもづくcomment1件は配列commentsから削除される。

it('適切なid値を送ると、idと合致するCommentが返ってくる、また該当のCommentは配列内から削除される', async () => {
  const oldComments = await getComments();

  const validId = 4;
  const response = await deleteComment(validId, 200);
  const comment = response.body;

  assert.deepStrictEqual(comment, {
    id: validId,
    username: comment.username,
    body: comment.body,
    createdAt: comment.createdAt,
    updatedAt: comment.updatedAt,
  });

  const currentComments = await getComments();

  assert.strictEqual(oldComments.length, currentComments.length + 1);
});

id値と合致するcommentがあった場合、合致したcomment1件、ステータスコード200が適切に返ってきていることを確認します。
それと同時に、deleteComment実行前と実行後の配列を比較して、comment1件が削除されていることを確認します。

以上のテストが全て正常に終了したら、今回のAPIサーバを用いた掲示板の作成は全て終了です。

最終的な環境

.
├── Task_info.md
├── app.js
├── controllers
│   └── comments.js
├── helper
│   └── requestHelper.js
├── index.js
├── models
│   └── Comment.js
├── package-lock.json
├── package.json
├── readme.md
├── routers
│   └── comments.js
└── test
    ├── app
    │   └── api
    │       ├── deleteComment.test.js
    │       ├── getComment.test.js
    │       ├── postComment.test.js
    │       └── putComment.test.js
    ├── mocha.opts
    └── models
        ├── createComment.test.js
        ├── findAll.test.js
        ├── removeComment.test.js
        └── updateComment.test.js

POSTMANを使用してDELETEリクエスト時の動きをチェックする(gif)

DELETErequest.gif

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0