Skip to content

Commit

Permalink
✨feat(catalogo): implementa middleware para validação de entrada de d…
Browse files Browse the repository at this point in the history
…ados | Parte 37

- Refatora o Controller "Atualizar Categoria" para Interceptar Erros e Usar Erros HTTP Apropriados
- Refatora o Controller "Deletar Categoria" para Interceptar Erros e Usar Erros HTTP Apropriados
- Implementa Classe Específica para Erro HTTP "400 Bad Request"
- Implanta "Middleware" Para Validação de Entrada de Dados da Rota "Inserir Categoria"
- Melhora Legibilidade dos Erros de Validação da Biblioteca "Zod"
- Implanta "Middleware" Para Validação de Entrada de Dados da Rota "Atualizar Categoria"
  • Loading branch information
diegoarmandoo committed Jan 14, 2024
1 parent 8325c8c commit 8263828
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 6 deletions.
23 changes: 22 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
"express": "^4.18.2",
"helmet": "^7.1.0",
"morgan": "^1.10.0",
"winston": "^3.11.0"
"winston": "^3.11.0",
"zod": "^3.22.4",
"zod-validation-error": "^2.1.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { HttpErrors } from "@shared/presentation/http/http.error";
import { NextFunction, Request, Response } from "express";
import { z, ZodSchema } from "zod";
import { fromZodError } from 'zod-validation-error';

const atualizarCategoriaSchema = z.object(
{
id: z.string().uuid(),
nome: z.string().min(3).max(50)
}
).strict();

const validaInputAtualizarCategoriaMiddleware = (
request: Request,
response: Response,
next: NextFunction) => {
try {
atualizarCategoriaSchema.parse(request.body);
next();
} catch (error: any) {
const validationError = fromZodError(error);
error = new HttpErrors.BadRequestError({message: validationError.message });
next(error);
}
}

export { validaInputAtualizarCategoriaMiddleware as validaInputAtualizarCategoria }
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { HttpErrors } from "@shared/presentation/http/http.error";
import { NextFunction, Request, Response } from "express";
import { z, ZodSchema } from "zod";
import { fromZodError } from 'zod-validation-error';

const inserirCategoriaSchema = z.object(
{
nome: z.string().min(3).max(50)
}
).strict();

const validaInputInserirCategoriaMiddleware = (
request: Request,
response: Response,
next: NextFunction) => {
try {
inserirCategoriaSchema.parse(request.body);
next();
} catch (error: any) {
const validationError = fromZodError(error);
error = new HttpErrors.BadRequestError({message: validationError.message });
next(error);
}
}

export { validaInputInserirCategoriaMiddleware as validaInputInserirCategoria }
6 changes: 3 additions & 3 deletions src/modules/catalogo/presentation/http/rest/categoria.http
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ POST http://{{host}}:{{port}}/{{apiversion}}/categorias
Content-type: application/json

{
"nome":"Sala de Televisão"
"nome":"Sala"
}

### Atualizar Categoria
PUT http://{{host}}:{{port}}/{{apiversion}}/categorias/ac6c99e0-0759-47c1-89cb-5c6dc6e64852
PUT http://{{host}}:{{port}}/{{apiversion}}/categorias/ac6c99e0-0759-47c1-89cb-5c6dc6e64853
Content-type: application/json

{
Expand All @@ -26,4 +26,4 @@ Content-type: application/json
}

### Deletar Categoria
DELETE http://{{host}}:{{port}}/{{apiversion}}/categorias/ac6c99e0-0759-47c1-89cb-5c6dc6e64852
DELETE http://{{host}}:{{port}}/{{apiversion}}/categorias/ac6c99e0-0759-47c1-89cb-5c6dc6e64853
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import express from 'express';
import { atualizarCategoriaController, deletarCategoriaController, inserirCategoriaController, recuperarCategoriaPorIdController, recuperarTodasCategoriasController } from './controllers';
import { contentType } from '@main/presentation/http/middlewares/content-type.middleware';
import { validaInputInserirCategoria } from '../middlewares/valida-input-inserir-categoria.middleware';
import { validaInputAtualizarCategoria } from '../middlewares/valida-input-atualizar-categoria.middleware';

const categoriaRouter = express.Router();

Expand All @@ -17,12 +19,14 @@ categoriaRouter.get(
categoriaRouter.post(
'/',
contentType,
validaInputInserirCategoria,
(request, response, next) => inserirCategoriaController.inserir(request, response, next)
)

categoriaRouter.put(
'/:id',
contentType,
validaInputAtualizarCategoria,
(request, response, next) => atualizarCategoriaController.atualizar(request, response, next)
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { CategoriaApplicationExceptions } from "@modules/catalogo/application/exceptions/categoria.application.exception";
import { AtualizarCategoriaUseCase } from "@modules/catalogo/application/use-cases/atualizar-categoria/atualizar-categoria.use-case";
import { RecuperarCategoriaProps } from "@modules/catalogo/domain/categoria/categoria.types";
import { ExpressController } from "@shared/presentation/http/express.controller";
import { HttpErrors } from "@shared/presentation/http/http.error";
import { NextFunction, Request, Response } from "express";

class AtualizarCategoriaExpressController extends ExpressController {
Expand All @@ -18,6 +20,9 @@ class AtualizarCategoriaExpressController extends ExpressController {
const categoriaAtualizada: boolean = await this._atualizarCategoriaUseCase.execute(categoriaInputDTO);
this.sendSuccessResponse(response,categoriaAtualizada);
} catch (error) {
if (error instanceof CategoriaApplicationExceptions.CategoriaNaoEncontrada){
error = new HttpErrors.NotFoundError({ message: error.message });
}
next(error);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { CategoriaApplicationExceptions } from "@modules/catalogo/application/exceptions/categoria.application.exception";
import { DeletarCategoriaUseCase } from "@modules/catalogo/application/use-cases/deletar-categoria/deletar-categoria.use-case";
import { ExpressController } from "@shared/presentation/http/express.controller";
import { HttpErrors } from "@shared/presentation/http/http.error";
import { NextFunction, Request, Response } from "express";

class DeletarCategoriaExpressController extends ExpressController {
Expand All @@ -17,6 +19,9 @@ class DeletarCategoriaExpressController extends ExpressController {
const categoriaDeletada: boolean = await this._deletarCategoriaUseCase.execute(uuid);
this.sendSuccessResponse(response,categoriaDeletada);
} catch (error) {
if (error instanceof CategoriaApplicationExceptions.CategoriaNaoEncontrada){
error = new HttpErrors.NotFoundError({ message: error.message });
}
next(error);
}
}
Expand Down
11 changes: 10 additions & 1 deletion src/shared/presentation/http/http.error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,18 @@ class UnsupportedMediaTypeError extends HttpError {
}
}

class BadRequestError extends HttpError {
constructor( params?: {statusCode?: number, message?: string}) {
const { statusCode, message} = params || {};
super(statusCode || 400, message || '⚠️ Servidor Não Pode ou Não Irá Processar a Requisição Devido a Algum Erro do Cliente (ex.: sintaxe de requisição mal formada, enquadramento de mensagem de requisição inválida ou requisição de roteamento enganosa.');
this.name = 'BadRequestError';
}
}

const HttpErrors = {
NotFoundError: NotFoundError,
UnsupportedMediaTypeError: UnsupportedMediaTypeError
UnsupportedMediaTypeError: UnsupportedMediaTypeError,
BadRequestError: BadRequestError
}

export { HttpError, HttpErrors }

0 comments on commit 8263828

Please sign in to comment.