Skip to content

Tratamento de Erros e Exceções

Neste projeto, o tratamento de erros é fundamentado no uso de Classes de Erro Customizadas e na Propagação de Exceções entre as camadas até chegar à Camada de Tela (Screen), que é a única responsável pela interação visual com o usuário.


1. Classes de Erro Customizadas

Todo erro de negócio ou de fluxo deve ser criado como uma classe que estende a classe nativa Error. Isso nos permite usar o operador instanceof para identificar o erro específico e tomar decisões baseadas nele.

Por que usar classes?

  • Tipagem Forte: O TypeScript reconhece o tipo do erro.
  • Contexto: Podemos adicionar propriedades extras à classe de erro (ex: statusCode, metadata).
  • Semântica: O nome da classe explica o que aconteceu (ex: UnauthorizedError).

2. Exemplo Real: Conflito de Perfis (409)

Imagine um cenário de login onde o usuário possui múltiplos perfis (ex: Admin e Doutor). A API retorna um erro 409 Conflict. A aplicação deve capturar isso, entender que se trata de múltiplos perfis e direcionar o usuário para uma tela de escolha.

Passo 1: Definição da Classe (Camada Application/Domain)

typescript
// src/actions/auth/errors/multiples-profile-error.ts

export class MultiplesProfileError extends Error {
  public readonly profiles: string[];

  constructor(profiles: string[]) {
    super("Usuário possui múltiplos perfis vinculados.");
    this.name = "MultiplesProfileError";
    this.profiles = profiles;
    
    // Necessário para que o instanceof funcione corretamente após a transpilação
    Object.setPrototypeOf(this, MultiplesProfileError.prototype);
  }
}

Passo 2: Captura e Transformação (Camada Application/Action)

A Action captura o erro bruto da API e o transforma em nossa classe de erro de domínio (ou apenas relança o erro).

typescript
// src/actions/auth/login.action.ts

export async function loginAction(credentials: Credentials) {
  try {
    const response = await api.post("/login", credentials);
    return response.data;
  } catch (error) {
    if (error.response?.status === 409) {
      // Transforma o erro 409 da API em um erro de domínio conhecido
      throw new MultiplesProfileError(error.response.data.profiles);
    }
    
    // Outros erros genéricos são apenas relançados para as camadas superiores
    throw error;
  }
}

Passo 3: Tratamento Visual (Camada Screen)

O Hook da tela captura o erro lançado pela Action (que atravessa a camada de Feature) e a Screen decide o que fazer.

typescript
// src/screens/Login/login-screen.hooks.ts

export function useLoginScreen() {
  const navigate = useNavigate();

  const handleLogin = async (data: Credentials) => {
    try {
      await loginAction(data);
      navigate("Home");
    } catch (error) {
      if (error instanceof MultiplesProfileError) {
        // Direciona para a tela de escolha de perfil com os dados do erro
        navigate("SelectProfile", { profiles: error.profiles });
        return;
      }

      // Tratamento visual (Toast) é EXCLUSIVO da Screen
      Toast.show({ title: "Erro", message: error.message, type: "error" });
    }
  };

  return { handleLogin };
}

3. Fluxo de Erro (Propagation)

A regra de ouro é: O erro deve subir as camadas.

  1. Action (Application): Captura o erro da API (Axios/Fetch), loga se necessário e faz o throw de uma classe customizada ou do erro bruto. Nunca exibe feedback visual.
  2. Rule/Feature: Pode capturar o erro para adicionar lógica de negócio ou apenas deixar passar.
  3. Screen Hook: Captura o erro final via try/catch ou pelo estado de erro do TanStack Query.
  4. Screen: Reage visualmente (Navegação, Toast, Modal ou Feedback inline).

4. Quando usar e Quando não usar

Usar quando:

  • O erro exige uma ação específica do usuário (ex: trocar senha, escolher perfil).
  • O erro precisa ser diferenciado de outros erros genéricos de rede.
  • Você precisa passar dados extras dentro do erro.

Não usar quando:

  • For um erro genérico de "Algo deu errado" que apenas mostrará um Toast padrão.
  • For um erro de sintaxe ou erro de programação (esses devem ser corrigidos, não tratados como fluxo).

5. Sintaxe Obrigatória para Componentes

Lembre-se que, ao exibir o erro em componentes de feedback, sempre use a sintaxe de function:

tsx
function ErrorFeedback({ message }: { message: string }) {
  return (
    <View style={styles.container}>
      <Icon name="error" />
      <Text>{message}</Text>
    </View>
  );
}