Rescue from errors with a grace
source link: https://www.tuicool.com/articles/hit/J7fQje7
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
How many times you had to deal with the external API’s errors in order to make your application behaves properly? You may end up then with the following code, especially when errors classes are generic:
class SomeAPIService def self.call perform_action rescue SomeAPI::Error => e if e.message.match(/account expired/) send_email_with_notification_about_expired_account elsif e.message.match(/api key invalid/) send_email_with_notification_about_invalid_api_key elsif e.message.match(/unauthorized action performed/) Rollbar.error('log some useful info') else raise(e) end end end
This code is far from being readable, easy-testable and perfect, isn’t it? If the external API does not provide custom error messages, we can create them on our side:
class SomeAPIAccountExpired < StandardError def self.===(exception) exception.class == SomeAPI::Error && exception.message.match(/account expired/) end end class SomeAPIInvalidAPIKey < StandardError def self.===(exception) exception.class == SomeAPI::Error && exception.message.match(/api key invalid/) end end class SomeAPIUnauthorizedAction < StandardError def self.===(exception) exception.class == SomeAPI::Error && exception.message.match(/unauthorized action performed/) end end
How does it work? When an error is raised, Ruby is checking the error class against the classes you have defined in the rescue
. If there is a match then the exception gets rescued. Every operator in Ruby is a method so we can define our version of ===
as well.
Having the above error classes defined, allows us to refactor our code in the following way:
class SomeAPIService def self.call perform_action rescue SomeAPIAccountExpired send_email_with_notification_about_expired_account rescue SomeAPIInvalidAPIKey send_email_with_notification_about_invalid_api_key rescue SomeAPIUnauthorizedAction Rollbar.error('log some useful info') end end
Now, we can test each error class separately and easily test the SomeAPIService
. The whole service’s code is also readable. We also don’t have to re-raise the error when we don’t support error message because it happens automatically as such error is not matched. That’s it!
Photo by Joe Calomeni from Pexels
Download free RSpec & TDD ebook
Do you want to earn more or jump to the next level in your company? Do you know that testing skills are one of the most desired skills? There is only first step: start testing and do it right. My ebook can help you. Subscribe to the newsletter to get a free copy of the book.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK