Percursos
/
Roc
Roc
/
Exercícios
/
Tratamento de Erros
Tratamento de Erros

Tratamento de Erros

Médio

Instruções

Implementa vários tipos de tratamento de erros e de gestão de recursos.

Um ponto importante da programação é saber tratar erros e fechar recursos mesmo quando ocorrem erros.

Este exercício pede que trates vários tipos de erros. Como o tratamento de erros depende bastante da linguagem de programação, tens de consultar os testes da tua track para veres exatamente o que é necessário.

Implementação

Estás a construir um pequeno servidor web que consulta uma base de dados de utilizadores ainda mais pequena. Parece fácil, mas no mundo real muitas coisas podem correr mal (e muitas vezes correm):

  • a ligação pode não ser segura: o URL tem de começar por "https://"
  • o nome do domínio pode ser inválido: neste exercício, deve ser "example.com"
  • a página pode não ser encontrada: só são permitidos "https://example.com/", "https://example.com/users/" e "https://example.com/users/<user_id>"
  • o user_id pode não ser um número inteiro positivo
  • pode não existir nenhum utilizador na base de dados com este user_id

Quando algo corre mal, é importante dar ao utilizador final uma mensagem de erro agradável e útil, para que este possa resolver o problema. Para isso, tens de garantir que o teu código propaga erros informativos desde o ponto onde o erro é detetado até ao ponto onde a mensagem de erro é produzida.

Felizmente, o Roc permite-te transportar uma carga útil (ou seja, dados) dentro da tua etiqueta Err. É tentador transportar diretamente uma mensagem de erro (por exemplo, Err("User #42 was not found")), e isso pode ser aceitável em alguns casos simples, mas tem várias limitações:

  • podes não ter contexto suficiente dentro da função que deteta o erro para produzir uma mensagem de erro suficientemente útil.
    • Por exemplo, a função Str.to_u64 pode ser usada para interpretar todo o tipo de números inteiros: dias, segundos, identificadores de utilizador e muito mais. Se a mensagem de erro disser apenas Could not convert string "0.5" to a positive integer, o utilizador pode não ter contexto suficiente para resolver o problema.
  • em muitos casos, o teu código de tratamento de erros pode precisar de tratar alguns erros de forma diferente dos outros. No entanto, se os erros transportarem apenas cargas úteis do tipo string, o teu código de tratamento de erros vai ter de interpretar essa string para saber que problema ocorreu: isto é ineficiente e pode facilmente deixar de funcionar se a mensagem de erro for alguma vez alterada.
  • se o teu site for multilingue, vais ter de traduzir a mensagem de erro para a língua do utilizador. Vai ser muito mais fácil fazê-lo se a carga útil do erro for constituída por dados que a máquina consegue interpretar, em vez de uma string em inglês.

Por isso, neste exercício, os teus erros vão antes transportar uma etiqueta com significado, acompanhada da sua própria carga útil informativa. Por exemplo, se o utilizador não for encontrado, o erro terá o aspeto Err(UserNotFound(42)).

Muito bem, vamos começar! Eis o que tens de fazer:

  1. Implementa get_user para devolver o utilizador pedido a partir da "base de dados" users (na verdade, é apenas um Dict). Certifica-te de que a função devolve Err(UserNotFound(user_id)) caso o utilizador não seja encontrado, em vez de Err(KeyNotFound).
  2. Implementa parse_user_id para interpretar o caminho do URL (como "/users/123") e obter um identificador de utilizador inteiro positivo (123). Em caso de erro, devolve Err(InvalidUserId(user_id_str)).
  3. Implementa getPage:
    • Se o URL for "https://example.com/", devolve Ok("Home page")
    • Se o URL for "https://example.com/users/", devolve Ok("Users page")
    • Se o URL for "https://example.com/users/<user_id>", interpreta o identificador de utilizador, carrega o utilizador com esse identificador e devolve Ok("<user name>'s page")
    • Se o prefixo do URL não for "https://", devolve Err(InsecureConnection(url))
    • Se o nome do domínio do URL não for "example.com", devolve Err(InvalidDomain(url))
    • Se o caminho não for /, /users/ ou /users/<user id>, devolve Err(PageNotFound(path))
    • Se o identificador de utilizador não for um número inteiro positivo, devolve Err(InvalidUserId(user_id_str))
    • Se o utilizador não existir, devolve Err(UserNotFound(user_id))
  4. Implementa error_essage para converter os erros anteriores em mensagens de erro traduzidas. A função deve, no mínimo, tratar inglês, mas és encorajado a tentar tratar também outra língua. As mensagens de erro em inglês devem ser assim:
  • "Insecure connection (non HTTPS): http://example.com/users/789"
  • "Invalid domain name: https://google.com/wrong"
  • "Page not found: /oops"
  • "User ID is not a positive integer: abc"
  • "User #42 was not found"

Nota: em vez de mostrar uma mensagem de erro ao utilizador quando este usa HTTP em vez de HTTPS, o teu servidor web podia redirecionar o navegador dele para HTTPS e o utilizador nem daria pelo erro. Como, em Roc, os erros são fáceis de interpretar por uma máquina, isto seria muito fácil de implementar.

Editar via GitHub A ligação abre numa nova janela ou separador
Roc Exercism

Estás pronto para começar Tratamento de Erros?

Inscreve-te no Exercism para aprenderes e dominares Roc com 126 exercícios, e mentoria humana real, tudo grátis.