Server handle exception and result
+++ +++
Server handle exception and result
One problem when we process requests from client is:
- What is format of result of response
- What is exception policy should be handle. For example, if client sent the bad request (bad query) then what is message response that server
need to notify to client ?
For above reasons, I will introdure 2 modules: -
_input_boundary.py
: the module will handle in request and wrap response toflask.Response
with json format -flask_api_handle.py
: the module will hook to handle when exception occurs
Input output boundrary
Because I want to send all of data in body (not in query parameters)
then I will to expose POST
method to client. For the request to JIRA server, we use GET
method
Client (Send POST) » Backend (Flask API - Receive POST, Send GET) » JIRA Server (REST - Receive GET)
-
Client send in Javascript:
async function _postRequest(url, data, onSuccess, onFailure) { // We can remove await to run parallel await axios .post(url, data, { headers: { "Content-type": "application/json", Accept: "application/json", }, }) .then((response) => { // console.log(response); onSuccess(response); }) .catch((error) => { console.log(error); const message = (error.response && error.response.data) || error.message; // (error.response && error.response.data["message"]) || error.message; const urlConfig = "config" in error && "url" in error.config && error.config.url; onFailure(message + ":" + urlConfig); }); }
-
Backend Flask API:
- Parse information in body json request (
parse_from_request
) - Forward to Rest Jira API server to process
- Parse the response and wrap with tuple of (code, data). The data will be transformed to json object
- Parse information in body json request (
Server handle exception
For above reasons, I want to make sure all of exception when be catched and re-direct to client to show up which detail error that server got (This one may be reveal some issue of security, we can use some other policy like log/notify…).
-
To do that I will create a decorator wrapping all of functions with
try..catch
to make sure all of exception will be catch and transform toServerException
instance.def with_server_error_handle(f): # We need to overwrite the name, because if keep default name ("_wrap_") then # in the view functions will have duplication URL mapping when we have more than 1 APIs @wraps(f) def _wrap_(*args, **kwargs): try: data = f(*args, **kwargs) return data except Exception as e: if isinstance(e, ServerException): raise e else: raise ServerException(e.code if hasattr(e, 'code') else 500, str(e))
- There are 2 points:
- Why we need to
@wrap
decorator: The@wrap
will be copy all of attribute of old function (f) into the new wrapped function. The copied attributes are: doc, name… The name is new name of function. If we don’t copy this one, may be if we have 2 functions then they will be duplicate in Flask App route table (mapping routes with functions). - Why we need to check
if isinstance(e, ServerException):
in exception. In the case we have nest function like this:In thef1(f2(some_exception_may_be_throw))
f2
may be we got the an exception, then we create newServerException
to pack this information. the exception will be raise tof1
. Inf1
the server exception will be catched. If we not raise this server exception, then we need create to new one. This process will be remove usefull information. After we have the method
- Why we need to
- There are 2 points:
-
Register customize
ServerException
in Flask app:def register_handle_server_exception(app: Flask, handle_func=handle_server_exception): """ Register handler function without using decorator. """ app.register_error_handler(ServerException, handle_func)