Os helpers são funções ou classes que fornecem funcionalidades comuns que podem ser reutilizadas em várias partes da aplicação. Eles ajudam a reduzir a duplicação de código e simplificar tarefas recorrentes.

Nova Estrutura do Projeto com Helpers

Vamos adicionar uma nova pasta helpers ao projeto, onde colocaremos funções auxiliares que podem ser utilizadas por qualquer camada.

Nova Estrutura do Projeto

src/
│
├── config/
│   └── database.ts
│
├── controllers/
│   └── userController.ts
│
├── helpers/
│   └── validationHelper.ts
│
├── models/
│   └── userModel.ts
│
├── repositories/
│   └── userRepository.ts
│
├── routes/
│   └── userRoutes.ts
│
├── migrations/
│   └── migrations.ts
│
├── server.ts

Implementação de Helpers

1. Validação de Email em helpers/validationHelper.ts

Um exemplo de helper pode ser a função de validação de e-mail, que será usada para garantir que os e-mails fornecidos pelos usuários sejam válidos.

export const isValidEmail = (email: string): boolean => {
  const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;
  return emailRegex.test(email);
};

2. Atualizando o Controller para Utilizar o Helper

Agora, no userController, vamos utilizar o helper isValidEmail para validar os e-mails antes de adicionar um novo usuário.

import { Request, Response } from 'express';
import { UserRepository } from '../repositories/userRepository';
import { isValidEmail } from '../helpers/validationHelper';

const userRepository = new UserRepository();

export const getUsers = async (req: Request, res: Response) => {
  try {
    const users = await userRepository.getAllUsers();
    res.status(200).json(users);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Erro ao buscar usuários' });
  }
};

export const addUser = async (req: Request, res: Response) => {
  const { name, email } = req.body;

  // Validando o e-mail com o helper
  if (!isValidEmail(email)) {
    return res.status(400).json({ error: 'Email inválido' });
  }

  try {
    const user = await userRepository.addUser(name, email);
    res.status(201).json(user);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Erro ao adicionar usuário' });
  }
};

Adicionando Camadas Auxiliares

As camadas auxiliares, como services ou use cases, podem ser utilizadas para encapsular a lógica de negócios e permitir que os controllers permaneçam enxutos e focados em lidar com as requisições.

1. Criando um Service para o Usuário em services/userService.ts

Vamos adicionar um serviço para encapsular a lógica de negócios relacionada aos usuários. Esse serviço vai lidar com a validação e chamar o repositório para manipular os dados.

import { UserRepository } from '../repositories/userRepository';
import { isValidEmail } from '../helpers/validationHelper';

export class UserService {
  private userRepository: UserRepository;

  constructor() {
    this.userRepository = new UserRepository();
  }

  async createUser(name: string, email: string) {
    if (!isValidEmail(email)) {
      throw new Error('Email inválido');
    }
    return await this.userRepository.addUser(name, email);
  }

  async listUsers() {
    return await this.userRepository.getAllUsers();
  }
}

2. Atualizando o Controller para Utilizar o Service

Agora, o controller vai delegar as responsabilidades ao UserService:

import { Request, Response } from 'express';
import { UserService } from '../services/userService';

const userService = new UserService();

export const getUsers = async (req: Request, res: Response) => {
  try {
    const users = await userService.listUsers();
    res.status(200).json(users);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Erro ao buscar usuários' });
  }
};

export const addUser = async (req: Request, res: Response) => {
  const { name, email } = req.body;

  try {
    const user = await userService.createUser(name, email);
    res.status(201).json(user);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
};