Estamos tentando desacoplar a biblioteca Express com o controller, que adicionará uma tarefa.
Quando tentamos fazer isso, tivemos um problema no arquivo taskRoutes.ts, pois ele espera um argumento, mas está recebendo dois. Isso acontece, pois o método handle() espera um httpRequest, como definimos internamente. Porém, estamos usando nas nossas rotas o Express, que espera essa nomenclatura com o rep e res.
É como se tivéssemos um notebook novo e tentássemos conectar em um monitor antigo. Geralmente monitores antigos possuem a saída VGA, enquanto o novo apenas HDMI. Dessa forma, não conseguimos fazer o encaixe, exceto se tivermos um adaptador do tipo VGA para HDMI, para que esses dois módulos consigam se comunicar.
O mesmo acontece nesse caso. Para o controller conseguir se comunicar com o Express, precisaremos criar um adaptador de rotas no Express.
Criando o adaptador de rotas no Express
Para isso, no VS Code, acessamos o Explorador na lateral esquerda da tela. Acessamos "src > adapters", na raiz dessa pasta, criaremos um arquivo. Então, acima, clicamos em "Novo arquivo", indicado pelo ícone de uma folha de papel dobrada na ponta. Nomeamos de expressRouteAdapter.ts.
expressRouteAdapter.ts
Começamos passando o export const expressRouteAdapter que receberá, entre parênteses, controller: Controller. Abrimos função e dentro retornaremos algo que o Express entende, nesse caso a função return async(req:Request, res:Response)=>{}.
import { Request, Response } from "express";
import { Controller } from "./interfaces/controller";
export const expressRouteAdapter = (controller: Controller) => {
return async (req: Request, res: Response) => {
}
Nas chaves, precisamos passar para o controller um objeto do tipo httpRequest e capturar o retorno, que será um httpResponse. Então, passamos controller.handle(httpRequest).
Mas quem que é esse httpRequest? Se no explorador acessarmos a pasta "interfaces" e abrirmos o arquivo http.ts, notamos que o httpRequest é alguém que possui um objeto do tipo body. Então, fechamos o arquivo e voltamos para o expressRouteAdapter.ts.
Sabendo disso, na linha acima de handle(), criamos o const httpRequest={}, nas chaves passamos body:req.body. Depois, na linha abaixo, antes de controller.handle(), passamos const httpResponse = await.
export const expressRouteAdapter = (controller: Controller) => {
return async (req: Request, res: Response) => {
const httpRequest = {
body: req.body,
};
const httpResponse = await controller.handle(httpRequest);
Agora, precisamos fazer uma verificação. Se o status de tarefa foi criada, ou seja, o 201, retornaremos um status e o body. Caso contrário, teremos que modificar o body para ser um erro.
Na linha abaixo, passamos if(httpResponse.statusCode=201){}. Nas chaves, passamos res.status(httpResponse.statusCode).json(). A mensagem JSON que retornaremos é o body, então, nos parênteses passamos httpResponse.body.
Caso isso não seja verdade, então else{} retornaremos um res.status(httpResponde.statusCode).json() passando no JSON o {error:httpResponse.body.message}, entre chaves, pois estamos retornando um objeto de erro.
import { Request, Response } from "express";
import { Controller } from "./interfaces/controller";
export const expressRouteAdapter = (controller: Controller) => {
return async (req: Request, res: Response) => {
const httpRequest = {
body: req.body,
};
const httpResponse = await controller.handle(httpRequest);
if (httpResponse.statusCode = 201) {
res.status(httpResponse.statusCode).json(httpResponse.body);
} else {
res
.status(httpResponse.statusCode)
.json({ error: httpResponse.body.message });
}
O adaptador está pronto. Agora, precisamos chamá-lo no arquivo taskRoutes.ts. Ao acessá-lo, podemos apagar todo o trecho de código após "/tasks". No lugar, adicionamos vírgula e passamos o adaptador expressRouteAdapter(addTaskController) e salvamos o arquivo.
taskRoutes.ts
import { Request, Response, Router } from "express";
import { AddTaskController } from "../../../controllers/task/addTask";
import { express RouteAdapter } from "../../../express RouteAdapter";
export default (router: Router): void => {
const addTaskController = new AddTaskController();
router.post("/tasks", expressRouteAdapter(addTaskController));
};
Feito isso, nosso servidor já está executando, caso o seu não esteja basta passar o comando npm start no terminal. Agora, podemos testar.
Com o Insomnia aberto, faremos nossas requisições. Temos uma requisição do tipo POST, apontando para http://localhost:3000/api/tasks que é onde criaremos nossas rotas. Não se preocupe, pois o projeto já está configurado para apontar para essa rota.
Basta passarmos um title, description e um date e enviar.
{
"title":"Title example",
"description": "one single description here!",
"date": "29/02/2024"
}
Depois, na lateral superior direita, clicamos no botão "Send" e temos o objeto sendo retornado logo abaixo e o status 201 criado.
Se analisarmos novamente o primeiro bloco do diagrama, percebemos que concluímos a parte da direita do controller. Separamos o que antes o controller estava ligado ao Express e acoplamos a biblioteca a um adaptador para podermos desacoplar o controller. Agora o controller depende de uma interface que o implemente, não dependemos mais de uma biblioteca externa.
Se futuramente precisarmos trocar de biblioteca, como trocar o Express pelo Fastify, basta alterarmos apenas o adaptador.
Da mesma forma que conseguimos fazer com o Express, precisaremos fazer com a nossa biblioteca de validação. É isso que faremos na sequência.
Te esperamos lá!