Post

Data Mapper Pattern no Frontend

A Definição:

O Data Mapper Pattern é uma técnica fundamental para a transferência eficiente e bidirecional de dados entre a camada de Domínio e a camada de Persistência.

Parece que é uma coisa super complicada, mas é bem simples: esse padrão garante que as camadas sejam independentes em relação a padronização de dados.

Aplicado ao frontend, vamos considerar camadas de Domínio e Persistência da seguinte forma:

Cada camada tem seu padrão de dados. Quando o frontend precisa se comunicar com uma API, é necessário tratar esses dados. O Data Mapper Pattern faz essa ponte entre Domínio e Persistência, na recepção e no envio (bidirecional) de dados. Isso torna cada camada independente da outra.

O Problema:

Na comunicação entre frontend e API, pode ser necessário manipular dados para que fiquem com o padrão esperado pela API. Qualquer mudança no formato dos dados na camada de Persistência pode resultar em uma cascata de atualizações em vários pontos do código, tornando a aplicação difícil de manter.

Por exemplo, se precisamos fazer um GET de informações de um usuário, mas a API usa snake_case, como "user_id":

{ "name": "Itallo Sá Vieira", "user_id": "123", "email": "", }

Se o padrão no frontend for camelCase, será necessário converter "user_id" para "userID". Se esse tratamento estiver no meio de componentes ou actions, vai gerar um código acoplado com as regras da camada de Persistência, nesse caso a API.

Se a API mudar seu padrão, isso impactará no código de componentes ou funções. Outro problema é, no caso do campo "email", se o backend mudar de string vazia para um null, precisaríamos atualizar todos os pontos onde fazemos essa validação.

Esse é um exemplo básico, mas imagine tratamentos para 20 campos diferentes e mais complexos.

Outro exemplo, agora com um envio de dados para API. É comum termos que montar o body para um POST assim:

const body = { user_name: props.name, user_id: props.userId, user_email: props.userEmail }

Essa abordagem torna o código confuso, especialmente se precisarmos repetir a montagem do corpo da requisição frequentemente. Qualquer mudança nos campos do backend vai exigir uma revisão extensa do código, resultando em retrabalho. A solução ideal é centralizar esse tipo de tratamento, simplificando a manutenção e reduzindo a probabilidade de erros futuros.

A Solução

Centralizar o tratamento de dados em um arquivo de Data Mapper para cada contexto.

Implementação:

Uma abordagem comum é colocar os Data Mappers próximos à camada de Persistência, como nas services que interagem com as APIs.

Por exemplo, considere a seguinte estrutura de pastas:

src/ ├── services/ └── services.js └── mappers/ └── userInfoMapper.js

Cada mapper é uma função que recebe um único objeto e retorna outro, aplicando as transformações necessárias.

Criando o método para trabalhar com um GET:

class UserInfoMapper { static toDomain(persistenceData) { const { user_name, user_id, user_email } = persistenceData; return { user: { name: user_name, id: user_id, email: user_email } } } }

Recebemos o formato da API e retornaremos no formato adequeado para o frontend.

Eu gosto de deixar esse tratamento o mais próximo das services.

Exemplo da montagem da service:

getUserInfo: async () => { const { data } = await http.get('/'); return UserInfoMapper.toDomain(data); }

Os dados retornados pela API já estarão tratados e prontos para uso na aplicação. Se o padrão da API for modificado, será necessário alterar apenas um arquivo.

O mesmo princípio se aplica aos dados enviados em uma requisição POST, exemplo:

class UserInfoMapper { // static toDomain... static toPersistence(domainData) { const user = domainData; return { user_name: user.name, user_id: user.id, user_email: user.email, } } }

Service:

sendUserInfo: async (obj) => { const body = UserInfoMapper.toPersistence(obj); return await http.post('/', body); }

Conclusão

O Data Mapper Pattern no frontend é uma técnica muito útil para manter a separação de responsabilidades entre as camadas de Domínio e Persistência. Centralizando o tratamento dos dados, o código fica mais modular, fácil de entender e menos suscetível a erros e independente de camadas externas. Incorporar Data Mappers na arquitetura frontend aumentará a qualidade e a facilidade de manutenção da aplicação.