-
Notifications
You must be signed in to change notification settings - Fork 14.3k
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
[SIP-41] Proposal for Alignment of Backend Error Handling #9298
Comments
Good initiative and now is a very good time to define the path forward. Adding a bit of more detail regarding new API implementation: Currently we are migrating MVC and "old" API's to new REST API's. At the same time we will refactor charts and dashboards to follow SIP-35 approved proposal. So, new API's that use PUT, POST, DELETE are planned to always call a command that implements the required business logic. A command will succeed or raise a defined custom exception, these exceptions are structured the following way:
A HTTP 422 {
"message": {
"database": [
"Database does not exist"
],
"owners": [
"Owners are invalid"
]
}
} Generic structure:
The main structure for errors come from FAB default |
Tagging @ktmud and linking to some of his thoughts on this topic from a PR comment: #10274 (comment) |
@john-bodley let's [VOTE] if we want to move this forward :) |
@john-bodley Let's vote this? |
I called a discussion on this today. |
This still needs to be put up for a vote. Here's the discuss thread. |
Since this is an old thread, can we revisit what's being proposed? I'm not sure I'm clear on it, and I know that this topic comes up quite a bit.
Is this what other people have been using as best practice recently? |
Pasting @betodealmeida's comments from his email which have some really useful points as well here for reference: With the Flask application error handlers already in place one can simply raise an exception anywhere in the code, and the backend will return a SIP-40 (#9194) compliant error payload. It greatly simplifies the API logic, since we can call commands outside a try/except block (see https://github.com/apache/superset/pull/13960/files#diff-f9deb9b63f5f2db38b811ff092cf90b0d4d558223f743bbbb5b203c203d2d590L607-L613). Note that many of the APIs are still using the @safe decorator from FAB, which prevents exceptions from bubbling up to Flask, and returns an error payload that is not SIP-40 compliant (https://github.com/apache/superset/pull/13960/files#diff-f9deb9b63f5f2db38b811ff092cf90b0d4d558223f743bbbb5b203c203d2d590L561). These should be removed regardless of the decision on SIP-41, but adopting Flask error handlers for SIP-41 means we can simply remove the decorator to return SIP-40 payloads. One controversial point is that in order to work correctly we need to define HTTP status codes on the exceptions ( superset/superset/exceptions.py Line 119 in 8eff5a7
|
@john-bodley do you intend to move this forward to a VOTE thread? |
@betodealmeida and @eschutho this is somewhat of an old thread and it seems like we never really got consensus on this. I think it might be prudent to close this (for now) and re-open it if/when we have more traction/alignment. |
Pointing out to #29330 which touches some of the things mentioned here. I'd love to get more direction from this SIP and identify some clear next steps. (we don't necessarily need a super strict end-goal, but some clear next steps in the right direction would help). My take on overall direction:
Some requirements/improvements I care about:
|
btw did we ever vote on this one. I'm a big yes on the ideas here, but the "done state" or direction is not clear enough. Let me re-open and invite another round of discussion. |
I think one of the biggest things to consider here is that SIP-40 was approved, but we still have many APIs that return an non-compatible error payload. Regardless of how we capture exceptions in the backend we need to make sure that the schema of the error returned in error messages follows SIP-40. This is particularly important for OAuth2, where OAuth2 is triggered by raising a special exception ( |
Interesting use case. I'm wondering if the contract of views generally be allowed to Another way to think about it is that views would be more in charge of doing their own error handling composing the right error-handling utils, and |
re-reading the SIP, the proposal is clear about going towards a consistent and well documented approach to error handling, it is not prescriptive about which approach to take. Let me try to propose something here and maybe we can promote this into the body of this SIP. Here's what the current SIP prescribes:
Let me give this a shot -> Preferred approach for error handling in Superset viewsHow exceptions are defined
How exceptions are implemented/used in viewsViews can simply raise the right exception while passing an error message for clarity, meaning the view shouldn't try and return an error-formatted payload (as in We generally would discourage the use of decorators in favor of the app-level safety net. This may need stripping decorators from existing views. [either that, or use a single How responses are generatedAll of the handling of exception and handling of generating a response is federated and handled in This may need some amount of taking over FAB, as FAB may already catch-and-respond in some cases. We may need to disable some things in FAB to get to our own solution in this area (?) Steps[TODO] |
I don't think FAB does anything with the errors — what's happening is that in many APIs we're using the |
Good to know, though now i wonder if I think we also have class-based views inheritance schemes in FAB, like @dpgaspar curious on your input here |
[SIP-41] Proposal for Alignment of Backend Error Handling
Motivation
[SIP-40] Proposal for Custom Error Messages proposes a unified pattern for handling API errors on the frontend however currently it is not apparent what error types (surfacing from the backend) need to be supported.
Reading through the code it is not super apparent:
Superset defines a number of exceptions each deriving from the
SupersetException
base class which contains an HTTP response status code in the [400, 600) range. Additionally there are a number of exceptions related to dataset commands.Raised Exceptions
It can be quite difficult to understand exactly where and when an exception will be handled. The Python community as a whole does a fairly poor job of documenting (sadly I sense a shortage of typing was not adding support for exceptions) what exception types a method can raise and thus from a development perspective tracing the exception flow can be challenging.
Error Handling
A common approach in Flask for handling errors is registering error handlers which can defined at either the application or blueprint level. This pattern is also supported by a number of the Flask RESTful extensions. Currently there only exists one registered error handler in Superset and one in FAB.
Even though Superset has a number of defined exceptions there is no consistent way in how these are propagated/handled and thus it is hard to do an audit on which errors exists. For example:
json_error_response
which wraps the Flask Response ensuring that the MIME type isapplication/json
. This is akin to this Flask error-handler example.SupersetException
is re-raised as aValidationError
.Response
where the MIME type isapplication/json
(per here).handle_api_exception
method is a decorator, rather than serving as a Flask error-handler and i.e.,Proposed Change
In order to better understand the various types of errors and scenarios in which they can surface I propose we undertake three broad approaches:
To address (2) and (3) personally I prefer the Flask error-handler approach, though due to our dependency on FAB we may need to align with that model.
I don't sense there's a quick fix for any of these steps, though I think there's merit in aligning on an approach which we can then i) manually enforce in code reviews, and ii) systematically refactor the code if necessary.
New or Changed Public Interfaces
There are no new or change public interfaces. This SIP merely proposes consolidating API error handling.
New dependencies
None.
Migration Plan and Compatibility
N/A.
Rejected Alternatives
None.
The text was updated successfully, but these errors were encountered: