0
0

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-05-11

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

GitHub

前提条件

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

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

実装する機能

「POST/api/comments」リクエストを送ると、新規にComment1件を作成し、作成されたCommentがレスポンス値として返ってくる機能の作成

この記事のまとめ

  • 新規にコメントを一件作成し、配列内にpushするメソッドを作成した
  • POSTリクエストした時のメソッドを作成した
  • POSTMANを用いたPOSTリクエスト時の動作チェックを行なった

新規にComment一件を作成し、作成されたCommentを返すメソッドの作成(createComment()

Comment.js
createComment: ({ username, body }) => {
  if (!username) {
    throw new Error('usernameは必須です');
  }
  if (!body) {
    throw new Error('bodyは必須です');
  }

  const comment = new Comment({
    username: username,
    body: body,
  });

  comments.push(comment);

  return comment;
},

メソッドの機能として、

  • usernameの引数に値が入っていない
  • bodyの引数に値が入っていない

場合はエラーを投げ、共に適切な値が入っている場合のみメソッドが成功するように設計しました。
それでは実際にうまく動作するかテストしてみようと思います

createComment()のテスト

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

テスト内容

  1. Comment.createCommentはメソッドである
  2. usernameの引数に値が入ってない場合エラーが返される
  3. bodyの引数に値が入ってない場合エラーが返される
  4. 適切なデータを渡した際、新たにコメントを一件作成し、そのコメント一件は返される
  5. 4.と同時に、Comment.findAllで返される配列には4.で作成したコメント一件が入っている

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

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

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

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

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

typeof演算子でcreateCommentがメソッド、関数オブジェクトであるかどうかテストします。

2 usernameの引数に値が入ってない場合エラーが返される

it('usernameの引数に値が入ってない場合エラーが返される', () => {
  const dataList = [{}, { body: 'test body' }];

  dataList.forEach(data => {
    try {
      Comment.createComment(data);
      assert.fail();
    } catch (error) {
      assert.equal(error.message, 'usernameは必須です');
    }
  });
});

先に空のオブジェクトとbodyにのみ引数が入っているオブジェクトが格納されている配列を作成し、forEachを使いそれらでcreateComment()を実行します。
createComment()がうまく実行されず、エラーになった場合、try/catch文により例外処理が行われ、catchにデータが受け取られます。
assert.equal()でエラーメッセージを比較し。適切なエラーメッセージが出た場合、テストは成功です。
もし、createComment()が問題なく実行された場合は、次行のassert.fail()というエラーを排出するメソッドが実行されるため、テストはエラーで終了、失敗となります。

3 bodyの引数に値が入ってない場合エラーが返される

it('bodyの引数に値が入ってない場合エラーが返される', () => {
  try {
    Comment.createComment({ username: 'test username' });
    assert.fail();
  } catch (error) {
    assert.equal(error.message, 'bodyは必須です');
  }
});

流れは2.と同じですが、こちらではcreateComment()に直接オブジェクトを入れています。
これは、2.では空オブジェクトを用意しましたが、3.で用意した場合、createComment()メソッドの流れ上、先にusernameでエラーが出るため、今回は必要ありません。

4 適切なデータを渡した際、新たにコメントを一件作成し、そのコメント一件は返される
5 4.と同時に、Comment.findAllで返される配列には4.で作成したコメント一件が入っている

it('適切なデータを渡した際、新規にコメントを1件作成して、そのコメント一件を返す、配列には新たなコメントが1件入っている', () => {
  const oldComments = Comment.findAll();
  const data = {
    username: 'test username',
    body: 'test body',
  };

  const newComment = Comment.createComment(data);
  assert.deepEqual(newComment, {
    id: newComment.id,
    username: data.username,
    body: data.body,
    createdAt: newComment.createdAt,
    updatedAt: newComment.updatedAt,
  });

  const currentComments = Comment.findAll();
  assert.equal(oldComments.length + 1, currentComments.length);
});

usernamebody共に引数が入っていた場合、createComment()は正常に実行され、
各プロパティには適切なデータが入っているどうか、assert.deepEqual()にてテストします。

また、それと同時に、作成されたデータはcommentsに格納されているかどうかも確認します。

createComment()を実行する前と後の配列を比較することは、現在のfindAll()ではできません。なぜなら、現在のfindAll()参照渡しのため、createComment()実行前にfindAll()を宣言しても、上書きされた参照値を返すため比較することができないからです。なので、コードを少し修正する必要があります。

変更前
findAll: () => {
  return comments;
},
変更後
findAll: () => {
  return comments.slice();
},

sliceメソッドを使用することにより、宣言時に新たな配列を返すことで、createComment実行前と後の配列の差を確認できます。

これらのテストがすべて成功することを確認したら、次はAPIリクエストをした時に、新規作成されたコメント一件が返ってくるメソッドを作成します。

POSTリクエスト時に動作するメソッドの実装

必要なライブラリのインストール

サーバー側でPOST処理するためのライブラリをインストールします

  • body-parser クライアントからPOST送信されたデータをreq.body経由で受け取れるようになります。

useを用いてミドルウェアからbody-parserを実行するようにします

app.js
const express = require('express');
const bodyParser = require('body-parser');

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

これで、body-parserが実行されるようになりました。
次は、POST送信されたデータを受け取り、コメントを新規作成するためのメソッドを作成します。

postComment()

postComment: (req, res) => {
  try {
    const { username, body } = req.body;
    const createdComment = Comment.createComment({ username, body });

    res.status(200).json(createdComment);
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
}

req.body経由で受け取ったデータをusername,bodyに挿入し、それを引数にcreateComment()を実行します。
実行に成功した場合、createComment()のデータをjson形式で返します。usernameまたはbodyのプロパティ値が無く、実行に失敗した場合は、エラーメッセージを返します。

それでは、postComment()メソッドが正常に実行するかどうかテストを行います。

postComment()のテスト

今回のテストも、APIの挙動を確認するためsupertestを使用しますが、記述するコードはgetComments.test.jsで記述したものとほとんど同じです。そして、今後も同じようなテストをする可能性があります。
なので今回はsupertestの処理を共通化し、自作ライブラリとして使用します。

requestHelper.js
const requestHelper = require('supertest');

const app = require('../app');

module.exports = {
  request: ({ method, endPoint, statusCode }) => {
    return requestHelper(app)
      [method](endPoint)
      .expect('Content-Type', /json/)
      .expect(statusCode);
  },
};

値が変わる部分は引数から代入します。

それでは、上記の関数を使って、postComment()のテストを行います

テスト内容

  1. titleを送らなかった場合400エラーとエラーメッセージが返る
  2. bodyを送らなかった場合400エラーとエラーメッセージが返る
  3. 適切なデータを送った場合、新規作成されたコメントが一件返される
  4. 3.と同時に、新規作成されたコメント1件がcomments配列に格納されている

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

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

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

  return response.body;
};

const requestComment = async (code, data) => {
  const response = await requestHelper
    .request({
      method: 'post',
      endPoint: '/api/comments',
      statusCode: code,
    })
    .send(data);
  return response;
};

describe('test 「POST /api/comments」', () => {
  // 以下にテストコードを記述します

});

getComments()は後々4.のテストにて配列の確認をするために使用します。

また、requestHelperでライブラリ化したコードも、ここで関数化しておきます。

1 titleを送らなかった場合400エラーとエラーメッセージが返る

it('usernameを送らなかった場合400エラーが返る', async () => {
  const data = { body: 'test body' };

  const response = await requestComment(400, data);

  assert.deepEqual(response.body, { message: 'usernameは必須です' });
});

もしusernameのプロパティ値がない場合、ステータスコードは400、そしてエラーメッセージが返ってくることを確認します。

2 bodyを送らなかった場合400エラーが返る

it('bodyを送らなかった場合`400`エラーとエラーメッセージが返る', async () => {
  const data = { username: 'test user' };

  const response = await requestComment(400, data);

  assert.deepEqual(response.body, { message: 'bodyは必須です' });
});

もしbodyのプロパティ値がない場合、ステータスコードは400、そしてエラーメッセージが返ってくることを確認します。

3 適切なデータを送った場合、新規作成されたコメントが一件返される
4 3.と同時に、新規作成されたコメント1件がcomments配列に格納されている

it('適切なデータを送った場合、新規作成されたコメントが一件返ってくる、また配列内には新規作成されたコメントが一件格納されている', async () => {
  const oldComments = await getComments();

  const data = { username: 'user', body: 'body' };

  const response = await requestComment(200, data);

  const comment = response.body;
  assert.deepEqual(comment, {
    id: comment.id,
    username: data.username,
    body: data.body,
    createdAt: comment.createdAt,
    updatedAt: comment.updatedAt,
  });

  const currentComments = await getComments();

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

はじめにgetComments()を実行し、新規作成されたコメントが入る前の配列をoldCommentsに代入します。

その後requestComment()を実行し、各プロパティ値のデータは適切かチェックします。
そしてこの時点で配列には新規作成されたコメントが入っているはずなので、その配列をcurrentCommentsに代入します。
そして、oldCommentsよりもcurrentCommentsの配列内が1つ多ければ、新規作成されたコメントは配列に格納されていることが判断きます。

これらのテストが完了したら、「「POST/api/comments」リクエストを送ると、新規にComment1件を作成し、作成されたCommentがレスポンス値として返ってくる機能の作成」は終了です。

現在の構成

tree
.
├── README.md
├── app.js
├── controllers
│   └── comments.js
├── helper
│   └── requestHelper.js
├── index.js
├── models
│   └── Comment.js
├── package-lock.json
├── package.json
├── routers
│   └── comments.js
└── test
    ├── app
    │   └── api
    │       ├── getComment.test.js
    │       └── postComment.test.js
    ├── mocha.opts
    └── models
        ├── createComment.test.js
        └── findAll.test.js

次は「「PUT/api/comments/:id」リクエストを送ると、id値に紐づいたComment1件を更新して、更新したComment1件がレスポンス値として返ってくる機能」の実装です。

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

おまけ:POSTMANを使用してPOSTリクエスト時の動きをチェックする

POSTメソッドは、フロント部分を作らないと実際に機能しているかどうかはわかりませんが、今回フロント部分の実装をする予定はありません。

なので今回はPOSTMANというツールを使って、起動したサーバーにPOSTメソッドでデータを送信します。

Postman | API Development Environment

使い方
APIの開発がむちゃくちゃ捗る「Postman」の使い方 - WPJ

POSTrequest.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