🆚Result Dart

Documentação: Uso do result_dart em Camadas Arquiteturais no Flutter

Esta documentação descreve como utilizar a biblioteca result_dart para tratar erros e sucessos de forma segura e escalável nas camadas de datasource, repository, e como apresentar os dados corretamente até a camada de view.


Motivação

O result_dart oferece uma abordagem funcional para lidar com sucessos e falhas, encapsulando o resultado de uma operação em objetos Success ou Failure. Isso elimina a necessidade de exceções no fluxo principal e facilita o manuseio de erros de maneira consistente.


Camadas Arquiteturais

1. Datasource

  • Responsabilidade: Comunicação direta com APIs ou bancos de dados.

  • Erros Tratados: Conexão, autenticação, e erros específicos de HTTP.

  • Retorno: Dados brutos (Map<String, dynamic>), encapsulados em AsyncResult.

Exemplo de Implementação

import 'package:result_dart/result_dart.dart';

class ExampleDatasourceImpl implements ExampleDatasource { final HttpClientInterface httpClient;

ExampleDatasourceImpl({required this.httpClient});

@override AsyncResult<Map<String, dynamic>, ExampleError> getExample() async { try { var result = await httpClient.get( 'todos/1', );

  return Success(result.data);
} on DioException catch (e) {
  if (e.response?.statusCode == 401) {
    return Failure(ExampleError("Usuário não autenticado."));
  } else if (e.response?.statusCode == 500) {
    return Failure(ExampleError("Erro interno da API."));
  }

  return Failure(
    ExampleError("Ocorreu um erro inesperado."),
  );
}

} }

2. Repository

  • Responsabilidade: Transformar os dados brutos do datasource em modelos de domínio.

  • Erros Tratados: Apenas repassa falhas do datasource.

  • Retorno: Modelo de domínio encapsulado em AsyncResult.

Exemplo de Implementação

import 'package:result_dart/result_dart.dart';

class ExampleRepositoryImpl implements IExampleRepository { final ExampleDatasource exampleDatasource;

ExampleRepositoryImpl({required this.exampleDatasource});

@override AsyncResult<ExampleModel, ExampleError> getExample() async { final result = await exampleDatasource.getExample();

return result.fold(
  (success) {
    return Success(ExampleModel.fromJson(success));
  },
  (failure) {
    return Failure(failure);
  },
);

} }

3. Usecase

  • Responsabilidade: Reunir dados de múltiplos repositórios ou aplicar lógica de negócios antes de passar para a camada superior.

  • Erros Tratados: Apenas repassa falhas do repositório.

  • Retorno: Dados prontos para consumo pela camada de apresentação.


4. View

  • Responsabilidade: Apresentar os dados ao usuário.

  • Erros Tratados: Exibir mensagens amigáveis baseadas no erro recebido.

  • Uso do Resultado: Consome os dados encapsulados e trata Success ou Failure.

Exemplo de Consumo na View

void fetchExampleData(ExampleRepository repository) async {
  final result = await repository.getExample();

  result.when(
    success: (data) {
      print("Dados recebidos: ${data.title}");
    },
    failure: (error) {
      print("Erro ao buscar dados: ${error.message}");
    },
  );
}

Fluxo Resumido

  1. Datasource:

    • Realiza a requisição HTTP.

    • Trata erros de API e conexão.

    • Retorna Success ou Failure com dados brutos.

  2. Repository:

    • Converte os dados brutos do datasource em modelos de domínio (ExampleModel).

    • Propaga erros para as camadas superiores.

  3. Usecase (opcional):

    • Aplica lógica de negócios.

    • Agrega dados de múltiplos repositórios.

  4. View:

    • Observa e consome o resultado (Success ou Failure).

    • Mostra os dados ou mensagens de erro ao usuário.


Benefícios

  • Tratamento Consistente de Erros: Todos os erros são encapsulados em Failure, simplificando o tratamento.

  • Lógica Centralizada: Parsing e validação ocorrem em um único lugar (repositório), mantendo o datasource limpo.

  • Facilidade de Teste: As camadas são desacopladas e podem ser testadas independentemente.

  • Código Funcional e Seguro: Operações encadeadas com fold evitam erros imprevisíveis no fluxo.

Last updated