From 6c4e188a51179018c8ff5779c82a62e1fcbb4113 Mon Sep 17 00:00:00 2001 From: Nathalia <64925426+nathalia-84@users.noreply.github.com> Date: Mon, 20 May 2024 17:23:28 -0300 Subject: [PATCH] feat: add getUser controller (#57) * feat: add getUser controller * feat: adjust userFindById controller * feat: add userFindById controller * feat: add userFindById controller * feat: add userFindById controller * feat: add userFindById controller * feat: create and test userFindById controller --- .../user/controllers/user-controller.test.ts | 81 ++++++++++++++++++- .../user/controllers/user-controller.ts | 29 ++++++- .../user/models/user-find-by-id-model.ts | 7 ++ .../user/routes/user-controller-factory.ts | 8 +- src/features/user/routes/user-routes.ts | 3 +- src/features/user/validators/index.ts | 1 + .../user/validators/user-find-by-id-schema.ts | 10 +++ 7 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 src/features/user/models/user-find-by-id-model.ts create mode 100644 src/features/user/validators/user-find-by-id-schema.ts diff --git a/src/features/user/controllers/user-controller.test.ts b/src/features/user/controllers/user-controller.test.ts index 6e00406..a7a535e 100644 --- a/src/features/user/controllers/user-controller.test.ts +++ b/src/features/user/controllers/user-controller.test.ts @@ -19,10 +19,21 @@ const makeSut = () => { } } + class UserFindByIdServiceStub implements Service { + public execute(params: any): any { + return params; + } + } + const validator = new ValidatorStub(); const userCreateService = new UserCreateServiceStub(); + const userFindByIdService = new UserFindByIdServiceStub(); - const userController = new UserController(validator, userCreateService); + const userController = new UserController( + validator, + userCreateService, + userFindByIdService + ); const req = mockDeep(); const res = mockDeep(); @@ -34,6 +45,7 @@ const makeSut = () => { res, userController, userCreateService, + userFindByIdService, validator, }; }; @@ -108,4 +120,71 @@ describe('[Controllers] UserController', () => { expect(next).toHaveBeenCalledWith(error); }); }); + + describe('userFindById', () => { + it('should call validator with correctly params', async () => { + const { next, req, res, userController, validator } = makeSut(); + + const validateSpy = vi.spyOn(validator, 'validate'); + + const uuid = crypto.randomUUID(); + + req.params = { id: uuid }; + req.path = '/users'; + + await userController.userFindById(req, res, next); + + expect(validateSpy).toHaveBeenCalledWith(expect.anything(), { + params: req.params, + path: req.path, + }); + }); + + it('should call service with correctly params', async () => { + const { next, req, res, userController, userFindByIdService } = makeSut(); + + const serviceSpy = vi.spyOn(userFindByIdService, 'execute'); + + const uuid = crypto.randomUUID(); + + req.params.id = uuid; + + await userController.userFindById(req, res, next); + + expect(serviceSpy).toHaveBeenCalledWith({ + id: req.params.id, + }); + }); + + it('should response 404 if user is not found', async () => { + const { next, req, res, userController, userFindByIdService } = makeSut(); + + const serviceSpy = vi.spyOn(userFindByIdService, 'execute'); + + const response = undefined; + + serviceSpy.mockReturnValue(response); + + const uuid = crypto.randomUUID(); + + req.params.id = uuid; + + await userController.userFindById(req, res, next); + + expect(res.status).toHaveBeenCalledWith(404); + }); + + it('should call next when an error', async () => { + const { next, req, res, userController, userFindByIdService } = makeSut(); + const error = new HttpError(500, 'error'); + + vi.spyOn(userFindByIdService, 'execute').mockRejectedValueOnce( + new HttpError(500, 'error') + ); + + await userController.userFindById(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); }); diff --git a/src/features/user/controllers/user-controller.ts b/src/features/user/controllers/user-controller.ts index 1c9ecbe..d7a8960 100644 --- a/src/features/user/controllers/user-controller.ts +++ b/src/features/user/controllers/user-controller.ts @@ -1,5 +1,6 @@ import type { UserCreateModel } from '../models/user-create-model.js'; -import { userCreateSchema } from '../validators/index.js'; +import { userCreateSchema, userFindByIdSchema } from '../validators/index.js'; +import type { UserFindByIdModel } from '../models/user-find-by-id-model.js'; import type { Controller } from '@/shared/protocols/controller.js'; import type { Service } from '@/shared/protocols/service.js'; import type { Validator } from '@/shared/infra/validator/validator.js'; @@ -26,8 +27,32 @@ export class UserController implements Controller { } }; + userFindById: AsyncRequestHandler = async (req, res, next) => { + try { + this.validator.validate(userFindByIdSchema, { + params: req.params, + path: req.path, + }); + + const user = await this.serviceFindById.execute({ + id: req.params.id, + }); + + if (!user) { + return res + .status(HttpStatusCode.notFound) + .json({ error: 'User not found' }); + } + + return res.status(HttpStatusCode.ok).json(user); + } catch (error) { + next(error); + } + }; + constructor( private validator: Validator, - private serviceCreate: Service + private serviceCreate: Service, + private serviceFindById: Service ) {} } diff --git a/src/features/user/models/user-find-by-id-model.ts b/src/features/user/models/user-find-by-id-model.ts new file mode 100644 index 0000000..0c7e9e3 --- /dev/null +++ b/src/features/user/models/user-find-by-id-model.ts @@ -0,0 +1,7 @@ +import type { UserModel } from './user-create-model.js'; + +export type UserFindByIdModel = { + id: string; +}; + +export type UserFindByIdResponse = null | UserModel; diff --git a/src/features/user/routes/user-controller-factory.ts b/src/features/user/routes/user-controller-factory.ts index 6e8db36..10ca7b3 100644 --- a/src/features/user/routes/user-controller-factory.ts +++ b/src/features/user/routes/user-controller-factory.ts @@ -4,12 +4,18 @@ import { UserController } from '../controllers/user-controller.js'; import { UserRepository } from '../repositories/user-repository/user-repository.js'; import { UserCreateService } from '../services/user-create-service.js'; import { Validator } from '@/shared/infra/validator/validator.js'; +import type { Service } from '@/shared/protocols/service.js'; export function userControllerFactory() { const userRepository = new UserRepository(); const userServiceFindAll = new UserCreateService(userRepository); + const userServiceFindById = {} as Service; const validator = new Validator(); - const userController = new UserController(validator, userServiceFindAll); + const userController = new UserController( + validator, + userServiceFindAll, + userServiceFindById + ); return { userController }; } diff --git a/src/features/user/routes/user-routes.ts b/src/features/user/routes/user-routes.ts index 892a4b6..bacff8b 100644 --- a/src/features/user/routes/user-routes.ts +++ b/src/features/user/routes/user-routes.ts @@ -7,8 +7,9 @@ const router = Router(); const { userController } = userControllerFactory(); router.post('/create', userController.create); +router.get('/:id', userController.userFindById); export default { - prefix: 'user', + prefix: 'users', router, }; diff --git a/src/features/user/validators/index.ts b/src/features/user/validators/index.ts index 8ad9576..0031493 100644 --- a/src/features/user/validators/index.ts +++ b/src/features/user/validators/index.ts @@ -1 +1,2 @@ export * from './user-create-schema.js'; +export * from './user-find-by-id-schema.js'; diff --git a/src/features/user/validators/user-find-by-id-schema.ts b/src/features/user/validators/user-find-by-id-schema.ts new file mode 100644 index 0000000..3bcdc24 --- /dev/null +++ b/src/features/user/validators/user-find-by-id-schema.ts @@ -0,0 +1,10 @@ +import Joi from 'joi'; + +export const userFindByIdParamsSchema = Joi.object({ + id: Joi.string().guid().required(), +}); + +export const userFindByIdSchema = Joi.object({ + params: userFindByIdParamsSchema, + path: Joi.string().required(), +});