From 6116c5fbdb82aaf45af88c291883705e93a95159 Mon Sep 17 00:00:00 2001 From: Talysson de Oliveira Cassiano Date: Sat, 7 Oct 2017 00:34:48 -0300 Subject: [PATCH] Implement serializers (#19) * Use serializers to generate JSON responses * Add new files to cleanup script --- scripts/cleanup.js | 4 +- src/container.js | 7 ++++ src/interfaces/http/user/UserSerializer.js | 10 +++++ src/interfaces/http/user/UsersController.js | 26 ++++++++---- .../http/user/UserSerializer.spec.js | 40 +++++++++++++++++++ 5 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 src/interfaces/http/user/UserSerializer.js create mode 100644 test/unit/interfaces/http/user/UserSerializer.spec.js diff --git a/scripts/cleanup.js b/scripts/cleanup.js index 97c9cfe..35bd784 100644 --- a/scripts/cleanup.js +++ b/scripts/cleanup.js @@ -28,10 +28,12 @@ const tasks = new Listr([ from: [ /\s*const \{(\n.*)+.*app\/user'\);/, /\s*const.*UsersRepository'\);/, + /\s*const.*UserSerializer'\);/, /\, User: UserModel/, /\s*usersRepository.*\}\]/, /\,\s*UserModel/, /\s+createUser(.|\n)+.*DeleteUser\n/, + /\s+userSerializer: UserSerializer\n/ ], to: '' }); @@ -44,10 +46,10 @@ const tasks = new Listr([ path.join(srcAndTestPath, 'app', 'user', '**'), path.join(srcAndTestPath, 'domain', 'user', '**'), path.join(srcAndTestPath, 'infra', 'user', '**'), + path.join(srcAndTestPath, 'interfaces', 'http', 'user', '**'), path.join(srcPath, 'infra', 'database', 'migrate', '*.js'), path.join(srcPath, 'infra', 'database', 'seeds', '*.js'), path.join(srcPath, 'infra', 'database', 'models', 'User.js'), - path.join(srcPath, 'interfaces', 'http', 'user', '**'), path.join(testPath, 'features', 'api', 'users', '**'), path.join(testPath, 'support', 'factories', '*.js') ]); diff --git a/src/container.js b/src/container.js index d6fd776..464d0ef 100644 --- a/src/container.js +++ b/src/container.js @@ -11,6 +11,8 @@ const { DeleteUser } = require('./app/user'); +const UserSerializer = require('./interfaces/http/user/UserSerializer'); + const Server = require('./interfaces/http/Server'); const router = require('./interfaces/http/router'); const loggerMiddleware = require('./interfaces/http/logging/loggerMiddleware'); @@ -65,4 +67,9 @@ container.registerClass({ deleteUser: DeleteUser }); +// Serializers +container.registerValue({ + userSerializer: UserSerializer +}); + module.exports = container; diff --git a/src/interfaces/http/user/UserSerializer.js b/src/interfaces/http/user/UserSerializer.js new file mode 100644 index 0000000..7fd1297 --- /dev/null +++ b/src/interfaces/http/user/UserSerializer.js @@ -0,0 +1,10 @@ +const UserSerializer = { + serialize({ id, name }) { + return { + id, + name + }; + } +}; + +module.exports = UserSerializer; diff --git a/src/interfaces/http/user/UsersController.js b/src/interfaces/http/user/UsersController.js index 1c97a58..ee4f935 100644 --- a/src/interfaces/http/user/UsersController.js +++ b/src/interfaces/http/user/UsersController.js @@ -6,6 +6,8 @@ const UsersController = { get router() { const router = Router(); + router.use(inject('userSerializer')); + router.get('/', inject('getAllUsers'), this.index); router.get('/:id', inject('getUser'), this.show); router.post('/', inject('createUser'), this.create); @@ -16,12 +18,14 @@ const UsersController = { }, index(req, res, next) { - const { getAllUsers } = req; + const { getAllUsers, userSerializer } = req; const { SUCCESS, ERROR } = getAllUsers.outputs; getAllUsers .on(SUCCESS, (users) => { - res.status(Status.OK).json(users); + res + .status(Status.OK) + .json(users.map(userSerializer.serialize)); }) .on(ERROR, next); @@ -29,13 +33,15 @@ const UsersController = { }, show(req, res, next) { - const { getUser } = req; + const { getUser, userSerializer } = req; const { SUCCESS, ERROR, NOT_FOUND } = getUser.outputs; getUser .on(SUCCESS, (user) => { - res.status(Status.OK).json(user); + res + .status(Status.OK) + .json(userSerializer.serialize(user)); }) .on(NOT_FOUND, (error) => { res.status(Status.NOT_FOUND).json({ @@ -49,12 +55,14 @@ const UsersController = { }, create(req, res, next) { - const { createUser } = req; + const { createUser, userSerializer } = req; const { SUCCESS, ERROR, VALIDATION_ERROR } = createUser.outputs; createUser .on(SUCCESS, (user) => { - res.status(Status.CREATED).json(user); + res + .status(Status.CREATED) + .json(userSerializer.serialize(user)); }) .on(VALIDATION_ERROR, (error) => { res.status(Status.BAD_REQUEST).json({ @@ -68,12 +76,14 @@ const UsersController = { }, update(req, res, next) { - const { updateUser } = req; + const { updateUser, userSerializer } = req; const { SUCCESS, ERROR, VALIDATION_ERROR, NOT_FOUND } = updateUser.outputs; updateUser .on(SUCCESS, (user) => { - res.status(Status.ACCEPTED).json(user); + res + .status(Status.ACCEPTED) + .json(userSerializer.serialize(user)); }) .on(VALIDATION_ERROR, (error) => { res.status(Status.BAD_REQUEST).json({ diff --git a/test/unit/interfaces/http/user/UserSerializer.spec.js b/test/unit/interfaces/http/user/UserSerializer.spec.js new file mode 100644 index 0000000..c65b3c2 --- /dev/null +++ b/test/unit/interfaces/http/user/UserSerializer.spec.js @@ -0,0 +1,40 @@ +const { expect } = require('chai'); +const UserSerializer = require('src/interfaces/http/user/UserSerializer'); +const User = require('src/domain/user/User'); + +describe('Interfaces :: HTTP :: User :: UserSerializer', () => { + it('returns id and name', () => { + const serializedUser = UserSerializer.serialize({ + id: 123, + name: 'The User' + }); + + expect(serializedUser).to.eql({ + id: 123, + name: 'The User' + }); + }); + + it('ignores extra attributes', () => { + const serializedUser = UserSerializer.serialize({ + id: 321, + name: 'The User', + unknown: 'Hello!' + }); + + expect(serializedUser).to.eql({ + id: 321, + name: 'The User' + }); + }); + + it('is able to serialize user entity instances', () => { + const user = new User({ id: 1, name: 'User :)' }); + const serializedUser = UserSerializer.serialize(user); + + expect(serializedUser).to.eql({ + id: 1, + name: 'User :)' + }); + }); +});