Parcours
/
Roc
Roc
/
Exercices
/
Gestion des erreurs
Gestion des erreurs

Gestion des erreurs

Moyen

Instructions

Implémente différentes formes de gestion des erreurs et des ressources.

Un aspect important de la programmation consiste à gérer les erreurs et à fermer les ressources même lorsque des erreurs se produisent.

Cet exercice te demande de gérer différents types d'erreurs. Comme la gestion des erreurs est plutôt spécifique au langage de programmation, tu devras consulter les tests de ton parcours pour voir ce qui est exactement attendu.

Implémentation

Tu construis un tout petit serveur web qui interroge une base de données d'utilisateurs encore plus petite. Ça a l'air simple, mais dans le monde réel, beaucoup de choses peuvent mal tourner (et c'est souvent le cas) :

  • la connexion peut ne pas être sécurisée : l'URL doit commencer par "https://"
  • le nom de domaine peut être invalide : dans cet exercice, il doit être "example.com"
  • la page peut être introuvable : seules "https://example.com/", "https://example.com/users/" et "https://example.com/users/<user_id>" sont autorisées
  • user_id n'est peut-être pas un entier positif
  • aucun utilisateur ne correspond peut-être à cet user_id dans la base de données

Quand quelque chose tourne mal, il est important de présenter à l'utilisateur final un message d'erreur clair et utile pour qu'il puisse résoudre le problème. Pour cela, ton code doit faire remonter des erreurs informatives depuis l'endroit où l'erreur est détectée jusqu'à l'endroit où le message d'erreur est produit.

Heureusement, Roc te permet de transporter une charge utile (c'est-à-dire des données) à l'intérieur de ton tag Err. Il est tentant de transporter directement un message d'erreur (par exemple Err("User #42 was not found")), et ça peut convenir dans certains cas simples, mais cette approche a plusieurs limites :

  • il se peut que tu n'aies pas, dans la fonction qui détecte l'erreur, assez de contexte pour produire un message d'erreur suffisamment utile.
    • Par exemple, la fonction Str.to_u64 peut servir à analyser toutes sortes d'entiers : des jours, des secondes, des identifiants d'utilisateur, et bien d'autres. Si le message d'erreur dit simplement Could not convert string "0.5" to a positive integer, l'utilisateur n'a peut-être pas assez de contexte pour résoudre le problème.
  • dans de nombreux cas, ton code de gestion des erreurs devra peut-être traiter certaines erreurs différemment des autres. Or, si les erreurs ne transportent comme charge utile qu'une string, ton code de gestion des erreurs devra analyser cette string pour savoir quel problème s'est produit : c'est inefficace et ça peut facilement casser si le message d'erreur vient à être modifié.
  • si ton site web est multilingue, tu devras traduire le message d'erreur dans la langue de l'utilisateur. Ce sera bien plus facile si la charge utile de l'erreur est constituée de données exploitables par une machine plutôt que d'une string en anglais.

Dans cet exercice, tes erreurs transporteront donc un tag explicite accompagné de sa propre charge utile. Par exemple, si l'utilisateur n'est pas trouvé, l'erreur ressemblera à Err(UserNotFound(42)).

Bon, c'est parti ! Voici ce que tu dois faire :

  1. Implémente get_user pour renvoyer l'utilisateur demandé depuis la « base de données » users (en réalité, ce n'est qu'un Dict). Vérifie que la fonction renvoie Err(UserNotFound(user_id)) quand l'utilisateur n'est pas trouvé, et non Err(KeyNotFound).
  2. Implémente parse_user_id pour convertir le chemin de l'URL (par exemple "/users/123") en un identifiant d'utilisateur entier positif (123). En cas d'erreur, renvoie Err(InvalidUserId(user_id_str)).
  3. Implémente getPage :
    • Si l'URL est "https://example.com/", renvoie Ok("Home page")
    • Si l'URL est "https://example.com/users/", renvoie Ok("Users page")
    • Si l'URL est "https://example.com/users/<user_id>", analyse l'identifiant d'utilisateur, charge l'utilisateur correspondant et renvoie Ok("<user name>'s page")
    • Si le préfixe de l'URL n'est pas "https://", renvoie Err(InsecureConnection(url))
    • Si le nom de domaine de l'URL n'est pas "example.com", renvoie Err(InvalidDomain(url))
    • Si le chemin n'est pas /, /users/ ou /users/<user id>, renvoie Err(PageNotFound(path))
    • Si l'identifiant d'utilisateur n'est pas un entier positif, renvoie Err(InvalidUserId(user_id_str))
    • Si l'utilisateur n'existe pas, renvoie Err(UserNotFound(user_id))
  4. Implémente error_essage pour convertir les erreurs précédentes en messages d'erreur traduits. La fonction doit au minimum gérer l'anglais, mais on t'encourage à essayer de gérer aussi une autre langue. Les messages d'erreur en anglais devraient ressembler à ceci :
  • "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"

Remarque : au lieu d'afficher un message d'erreur à l'utilisateur qui utilise HTTP au lieu de HTTPS, ton serveur web pourrait rediriger son navigateur vers HTTPS, et l'utilisateur ne remarquerait même pas l'erreur. Comme les erreurs sont exploitables par une machine en Roc, ce serait très facile à implémenter.

Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Roc Exercism

Prêt à commencer Gestion des erreurs ?

Inscris-toi sur Exercism pour apprendre et maîtriser Roc avec 126 exercices, et un vrai mentorat humain, le tout gratuitement.