配列を仮想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()
)
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
ファイルを新たに作成し、そちらでテストを行なっていきます。
テスト内容
-
Comment.createComment
はメソッドである -
username
の引数に値が入ってない場合エラーが返される -
body
の引数に値が入ってない場合エラーが返される - 適切なデータを渡した際、新たにコメントを一件作成し、そのコメント一件は返される
-
4.
と同時に、Comment.findAll
で返される配列には4.
で作成したコメント一件が入っている
この5点を確認するテストコードを記述していきます
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);
});
username
、body
共に引数が入っていた場合、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
を実行するようにします
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
の処理を共通化し、自作ライブラリとして使用します。
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()
のテストを行います
テスト内容
-
title
を送らなかった場合400
エラーとエラーメッセージが返る -
body
を送らなかった場合400
エラーとエラーメッセージが返る - 適切なデータを送った場合、新規作成されたコメントが一件返される
-
3.
と同時に、新規作成されたコメント1件がcomments
配列に格納されている
この4点を確認するテストコードを記述します
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
がレスポンス値として返ってくる機能の作成」は終了です。
現在の構成
.
├── 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