-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor errors #213
base: main
Are you sure you want to change the base?
Refactor errors #213
Conversation
@@ -108,6 +109,7 @@ class GatewayTimeout < HTTPStatusError; end # 504 | |||
UnprocessableEntity => [422, 'Unprocessable entity'], | |||
TooManyRequests => [429, 'Too many requests'], | |||
InternalServerError => [500, 'Internal server error'], | |||
HTTPStatusError => [500, 'Unspecified'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pedro The original idea here was that HTTPStatusError
would behave more like an abstract class which would never be instantiated directly; which is also why it didn't get an entry in this table. What do you think of changing this to just raising an ArgumentError
if the instantiated error class wasn't found in META
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, makes sense! changing it.
@pedro Nice job. Left a few minor comments, but +1 from me! |
@pedro I'd love to see this merged. Is there anything that needs to be fixed or can it be merged? |
it's not supposed to be instantiated directly unless you pass all the required error attributes
better conforming to regular ruby exception classes
@brandur @gudmundur hey folks, good time to follow up on this – I just had to refactor how we handle errors at Lugg and ended up with a mix of Pliny and new stuff we're super happy about. It's not a huge departure from this. This basically highlights the issue:
Ruby exceptions are meant to have a message, but we all know API errors really just need an id. They are easier to compare in tests, and they won't pollute code with copy that we all know should live under But no one said that the Ruby exception message is what we render to end-users. "invalid_json" works perfectly fine as the internal exception message, and it also happens to be a good error identifier for Pliny APIs, not to mention a good key to lookup the corresponding entry in the locales file. So here's the proposal: Pliny ships with i18n. All existing user error messages are set there (like "Unauthorized" and "Unprocessable entity"). Our base error class only requires an id, which is used to fetch these messages and save them as the You can then test for these exceptions using standard matchers, like: expect { run }.to raise_error(Pliny::Errors::BadRequest, "invalid_json") Finally, while in there I'd also like to remove all exception classes outside 4xx and 5xx. Because if you want to render a 30x, for instance, you should rely on Sinatra's helpers and not on a Pliny exception. Thoughts? |
@pedro 💯 👍 |
I like it (both taking the messages out with default localization and removing non-4/5xx series exceptions). +1. |
I really like this idea as well. |
you folks rock, thanks for the feedback! updated to match then 💃 |
This is looking nice. The only comment I have is from a non-native english perspective. If I were to wish to translate error messages, I wouldn't be able to do the following:
It's probably an edge case though. |
class BadGateway < HTTPStatusError; end # 502 | ||
class ServiceUnavailable < HTTPStatusError; end # 503 | ||
class GatewayTimeout < HTTPStatusError; end # 504 | ||
def self.MakeError(status, id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this method name be snakecased?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh god, yes. I think I saw this class-looking method used before for a similar purpose but looking now it's super confusing. Fixed!
@dmathieu Should be easy enough to just move the translation over to be execute on access of @pedro Left a minor comment above, but looks good to me! +1. |
My thinking was more to actually lazily fetch this data (and maybe memoize it to avoid expensive i18n lookup calls).
|
Ah! I guess the only thing there is that with that implementation you could produce another failure scenario that's not too different from the one you have above: error = Pliny::Errors::BadRequest.new
error.user_message #=> memoized
I18n.locale = :fr
error.user_message #=> will show the error in english Although admittedly, also probably unlikely in practice. |
facilitate error messages in other languages
good point. moved to a method not memoized for now, don't think we should worry too much about optimizing exceptional paths. |
👍 |
If that's actually an issue in practice could you memoize keyed against the current locale, something like |
class SeeOther < HTTPStatusError; end # 303 | ||
class NotModified < HTTPStatusError; end # 304 | ||
class UseProxy < HTTPStatusError; end # 305 | ||
class TemporaryRedirect < HTTPStatusError; end # 307 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that removing all the non 4xx-5xx error classes is going to cause things to break in a few of my apps. To make matters a little worse, I suspect a few of them might be used for control flow.
That said, I do think this is a good change and what I've been doing is BAD (tm).
@gudmundur nod on the breaking changes – this would obviously require a major version bump normally, but seeing that we're still on the 0.x series I'm not sure there's much else we can do. Thoughts? |
@pedro It's kind of a departure from the proposal above, should we allow an override message to be given for backward compatibility (and make that route deprecated, or at least unusual)? I guess the disadvantage is developers not knowing that they usually shouldn't provide it, but that's not a huge downside. Definitely like the original proposal as is, but given that Pliny's seeing a reasonable amount of use now, erring on the side of conservative interface changes is probably a good idea. |
Sequel::NoMatchingRow
errors