Реалізуйте різні види обробки помилок і керування ресурсами.
У програмуванні важливо вміти обробляти помилки та закривати ресурси, навіть якщо вони виникають.
У цій вправі потрібно обробити різні помилки. Оскільки обробка помилок досить специфічна для конкретної мови програмування, потрібно звернутися до тестів своєї мови, щоб побачити, що саме вимагається.
Ми створюємо крихітний вебсервер, який робить запити до ще крихітнішої бази даних користувачів. Звучить просто, але в реальному світі багато що може піти не так (і часто йде):
"https://"
"example.com"
"https://example.com/", "https://example.com/users/" і "https://example.com/users/<user_id>"
user_id може не бути додатним цілим числомuser_id може не бути в базі данихКоли щось іде не так, важливо дати кінцевому користувачеві зрозуміле й корисне повідомлення про помилку, щоб він міг зарадити проблемі. Для цього потрібно, щоб наш код передавав інформативні помилки від місця, де помилку виявлено, до місця, де формується повідомлення про неї.
На щастя, Roc дозволяє передавати корисне навантаження (тобто дані) всередині тегу Err. Спокусливо передавати повідомлення про помилку напряму (наприклад, Err("User #42 was not found")), і в деяких простих випадках це цілком прийнятно, але має кілька обмежень:
Str.to_u64 можна використати, щоб розібрати найрізноманітніші цілі числа: дні, секунди, ідентифікатори користувачів тощо. Якщо повідомлення про помилку просто каже Could not convert string "0.5" to a positive integer, користувачеві може бракувати контексту, щоб зарадити проблемі.Тож у цій вправі наші помилки замість цього нестимуть змістовний тег разом із власним корисним навантаженням. Наприклад, якщо користувача не знайдено, помилка матиме такий вигляд: Err(UserNotFound(42)).
Гаразд, почнімо! Ось що потрібно зробити:
get_user, щоб повертати запитаного користувача з «бази даних» users (насправді це просто Dict). Обовʼязково повертайте Err(UserNotFound(user_id)), якщо користувача не знайдено, а не Err(KeyNotFound).parse_user_id, щоб перетворювати шлях URL (наприклад, "/users/123") на додатне ціле число, тобто ідентифікатор користувача (123). У разі помилки повертайте Err(InvalidUserId(user_id_str)).getPage:
"https://example.com/", повертайте Ok("Home page")
"https://example.com/users/", повертайте Ok("Users page")
"https://example.com/users/<user_id>", розберіть ідентифікатор користувача, завантажте користувача з цим ідентифікатором і поверніть Ok("<user name>'s page")
"https://", повертайте Err(InsecureConnection(url))
"example.com", повертайте Err(InvalidDomain(url))
/, не /users/ і не /users/<user id>, повертайте Err(PageNotFound(path))
Err(InvalidUserId(user_id_str))
Err(UserNotFound(user_id))
error_essage, щоб перетворювати попередні помилки на перекладені повідомлення про помилки. Функція має принаймні опрацьовувати англійську, але радимо спробувати й іншу мову. Англійські повідомлення про помилки мають мати такий вигляд:"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"Примітка: замість того щоб показувати користувачеві повідомлення про помилку, коли він використовує HTTP замість HTTPS, наш вебсервер міг би перенаправити його браузер на HTTPS, і користувач навіть не помітив би помилки. Оскільки в Roc помилки машиночитні, реалізувати це було б дуже просто.