def handle_error(self, e): ''' Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param Exception e: the raised Exception object ''' got_request_exception.send(current_app._get_current_object(), exception=e) headers = Headers() if e.__class__ in self.error_handlers: handler = self.error_handlers[e.__class__] result = handler(e) default_data, code, headers = unpack(result, 500) elif isinstance(e, HTTPException): code = e.code default_data = { 'message': getattr(e, 'description', HTTP_STATUS_CODES.get(code, '')) } headers = e.get_response().headers elif self._default_error_handler: result = self._default_error_handler(e) default_data, code, headers = unpack(result, 500) else: code = 500 default_data = { 'message': HTTP_STATUS_CODES.get(code, str(e)), } default_data['message'] = default_data.get('message', str(e)) data = getattr(e, 'data', default_data) fallback_mediatype = None if code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) elif code == 404 and current_app.config.get("ERROR_404_HELP", True): data['message'] = self._help_on_404(data.get('message', None)) elif code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" # Remove blacklisted headers for header in HEADERS_BLACKLIST: headers.pop(header, None) resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not hasattr(e, 'code') and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e code = getattr(e, 'code', 500) data = getattr(e, 'data', error_data(code)) if code >= 500: # There's currently a bug in Python3 that disallows calling # logging.exception() when an exception hasn't actually be raised if sys.exc_info() == (None, None, None): current_app.logger.error("Internal Error") else: current_app.logger.exception("Internal Error") help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404 and ('message' not in data or data['message'] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] += ". " else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) resp = self.make_response(data, code) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(self.app, exception=e) if not hasattr(e, 'code') and self.app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: exc = exc_type(exc_value) exc.__traceback__ = tb raise exc else: raise e code = getattr(e, 'code', 500) data = getattr(e, 'data', error_data(code)) if code >= 500: # There's currently a bug in Python3 that disallows calling # logging.exception() when an exception hasn't actually be raised if sys.exc_info() == (None, None, None): self.app.logger.error("Internal Error") else: self.app.logger.exception("Internal Error") if code == 404 and ('message' not in data or data['message'] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in self.app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] += ". " else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join((rules[match] for match in close_matches)) + ' ?' resp = self.make_response(data, code) if code == 401: resp = unauthorized(resp, self.app.config.get("HTTP_BASIC_AUTH_REALM", "flask-restful")) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(self.app, exception=e) if not hasattr(e, "code") and self.app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e code = getattr(e, "code", 500) data = getattr(e, "data", error_data(code)) if code >= 500: # There's currently a bug in Python3 that disallows calling # logging.exception() when an exception hasn't actually be raised if sys.exc_info() == (None, None, None): self.app.logger.error("Internal Error") else: self.app.logger.exception("Internal Error") if code == 404 and ("message" not in data or data["message"] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub("(<.*>)", "", rule.rule), rule.rule) for rule in self.app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] += ". " else: data["message"] = "" data["message"] += ( "You have requested this URI [" + request.path + "] but did you mean " + " or ".join((rules[match] for match in close_matches)) + " ?" ) resp = self.make_response(data, code) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """ Almost identical to Flask-Restful's handle_error, but fixes some minor issues. Specifically, this fixes exceptions so they get propagated correctly when ``propagate_exceptions`` is set. """ if not hasattr(e, 'code') and self.app.propagate_exceptions: got_request_exception.send(self.app, exception=e) raise return super(APIController, self).handle_error(e)
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(self, exception=e) code = getattr(e, 'code', 500) data = getattr(e, 'data', error_data(code)) if code >= 500: self.app.logger.exception("Internal Error") if code == 404 and ('message' not in data or data['message'] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in self.app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] += ". " else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join((rules[match] for match in close_matches)) + ' ?' resp = self.make_response(data, code) if code == 401: resp = unauthorized(resp, self.app.config.get("HTTP_BASIC_AUTH_REALM", "flask-restful")) return resp
def handle_error(self, e): ''' Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param Exception e: the raised Exception object ''' got_request_exception.send(current_app._get_current_object(), exception=e) include_message_in_response = current_app.config.get("ERROR_INCLUDE_MESSAGE", True) default_data = {} headers = Headers() for typecheck, handler in six.iteritems(self._own_and_child_error_handlers): if isinstance(e, typecheck): result = handler(e) default_data, code, headers = unpack(result, HTTPStatus.INTERNAL_SERVER_ERROR) break else: if isinstance(e, HTTPException): code = HTTPStatus(e.code) if include_message_in_response: default_data = { 'message': getattr(e, 'description', code.phrase) } headers = e.get_response().headers elif self._default_error_handler: result = self._default_error_handler(e) default_data, code, headers = unpack(result, HTTPStatus.INTERNAL_SERVER_ERROR) else: code = HTTPStatus.INTERNAL_SERVER_ERROR if include_message_in_response: default_data = { 'message': code.phrase, } if include_message_in_response: default_data['message'] = default_data.get('message', str(e)) data = getattr(e, 'data', default_data) fallback_mediatype = None if code >= HTTPStatus.INTERNAL_SERVER_ERROR: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) elif code == HTTPStatus.NOT_FOUND and current_app.config.get("ERROR_404_HELP", True) \ and include_message_in_response: data['message'] = self._help_on_404(data.get('message', None)) elif code == HTTPStatus.NOT_ACCEPTABLE and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" # Remove blacklisted headers for header in HEADERS_BLACKLIST: headers.pop(header, None) resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) if code == HTTPStatus.UNAUTHORIZED: resp = self.unauthorized(resp) return resp
def handle_error(self, e): ''' Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param Exception e: the raised Exception object ''' got_request_exception.send(current_app._get_current_object(), exception=e) # When propagate_exceptions is set, do not return the exception to the # client if a handler is configured for the exception. if not isinstance(e, HTTPException) and \ current_app.propagate_exceptions and \ not isinstance(e, tuple(self.error_handlers.keys())): exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e include_message_in_response = current_app.config.get( "ERROR_INCLUDE_MESSAGE", True) default_data = {} headers = Headers() for typecheck, handler in six.iteritems( self._own_and_child_error_handlers): if isinstance(e, typecheck): result = handler(e) default_data, code, headers = unpack( result, HTTPStatus.INTERNAL_SERVER_ERROR) break else: if isinstance(e, HTTPException): code = HTTPStatus(e.code) if include_message_in_response: default_data = { 'message': getattr(e, 'description', code.phrase) } headers = e.get_response().headers elif self._default_error_handler: result = self._default_error_handler(e) default_data, code, headers = unpack( result, HTTPStatus.INTERNAL_SERVER_ERROR) else: code = HTTPStatus.INTERNAL_SERVER_ERROR if include_message_in_response: default_data = { 'message': code.phrase, } if include_message_in_response: default_data['message'] = default_data.get('message', str(e)) data = getattr(e, 'data', default_data) fallback_mediatype = None if code >= HTTPStatus.INTERNAL_SERVER_ERROR: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) elif code == HTTPStatus.NOT_FOUND and current_app.config.get("ERROR_404_HELP", True) \ and include_message_in_response: data['message'] = self._help_on_404(data.get('message', None)) elif code == HTTPStatus.NOT_ACCEPTABLE and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[ 0] if supported_mediatypes else "text/plain" # Remove blacklisted headers for header in HEADERS_BLACKLIST: headers.pop(header, None) resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) if code == HTTPStatus.UNAUTHORIZED: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not hasattr(e, 'code') and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e code = getattr(e, 'code', 500) data = getattr(e, 'data', error_data(code)) headers = {} if code >= 500: # There's currently a bug in Python3 that disallows calling # logging.exception() when an exception hasn't actually be raised if sys.exc_info() == (None, None, None): current_app.logger.error("Internal Error") else: current_app.logger.exception("Internal Error") help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404 and ('message' not in data or data['message'] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] += ". " else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' if code == 405: headers['Allow'] = e.valid_methods error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype = fallback_mediatype ) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) is_http_exception = isinstance(e, HTTPException) if not is_http_exception and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: # pragma: no cover raise e if is_http_exception: code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } else: code = 500 default_data = { 'message': http_status_message(code), } data = getattr(e, 'data', default_data) headers = {'Access-Control-Allow-Origin': '*'} if code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: # pragma: no cover exc_info = None current_app.log_exception(exc_info) help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404: rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and # continue it. if "message" in data: data["message"] = data["message"].rstrip('.') + '. ' else: # pragma: no cover data["message"] = "" data['message'] += ('You have requested this URI [' + request.path + '] but did you mean ' + ' or '.join( (rules[match] for match in close_matches)) + ' ?') if code == 405: headers['Allow'] = e.valid_methods enhanced_data = copy.deepcopy(envelope) enhanced_data.update(copy.deepcopy(error_meta)) enhanced_data["meta"]["error_type"] = e.__class__.__name__ enhanced_data["meta"]["code"] = code enhanced_data["meta"]["error_message"] = data['message'] resp = self.make_response(enhanced_data, code, headers) if code == 401: # pragma: no cover resp = self.unauthorized(resp) return resp
def handle_error(self, e): ''' Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param Exception e: the raised Exception object ''' got_request_exception.send(current_app._get_current_object(), exception=e) headers = Headers() if e.__class__ in self.error_handlers: handler = self.error_handlers[e.__class__] result = handler(e) default_data, code, headers = unpack(result, 500) elif isinstance(e, HTTPException): code = e.code default_data = { 'message': getattr(e, 'description', HTTP_STATUS_CODES.get(code, '')) } headers = e.get_response().headers elif self._default_error_handler: result = self._default_error_handler(e) default_data, code, headers = unpack(result, 500) else: code = 500 default_data = { 'message': HTTP_STATUS_CODES.get(code, str(e)), } default_data['message'] = default_data.get('message', str(e)) data = getattr(e, 'data', default_data) fallback_mediatype = None if code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) elif code == 404 and current_app.config.get("ERROR_404_HELP", True): data['message'] = self._help_on_404(data.get('message', None)) elif code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[ 0] if supported_mediatypes else "text/plain" # Remove blacklisted headers for header in HEADERS_BLACKLIST: headers.pop(header, None) resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e headers = Headers() if isinstance(e, HTTPException): code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } headers = e.get_response().headers else: code = 500 default_data = { 'message': http_status_message(code), } # Werkzeug exceptions generate a content-length header which is added # to the response in addition to the actual content-length header # https://github.com/flask-restful/flask-restful/issues/534 remove_headers = ('Content-Length', ) for header in remove_headers: headers.pop(header, None) data = getattr(e, 'data', default_data) if code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404: rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] = data["message"].rstrip('.') + '. ' else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[ 0] if supported_mediatypes else "text/plain" resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): got_request_exception.send(current_app._get_current_object(), exception=e) if not hasattr(e, 'code') and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e code = getattr(e, 'code', 500) data = getattr(e, 'data', error_data(code)) headers = {} if code >= 500: if sys.exc_info() == (None, None, None): current_app.logger.error("Internal Error") else: current_app.logger.exception("Internal Error") help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404 and ('message' not in data or data['message'] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: if "message" in data: data["message"] += ". " else: data["message"] = "" data['message'] += 'You have requested this URI [' + \ request.path + '] but did you mean ' + ' or '.join(( rules[match] for match in close_matches)) + ' ?' if code == 405: headers['Allow'] = e.valid_methods error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] \ if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype=fallback_mediatype, ) else: if code == 400 and current_app.config.get( 'CHANGE_400_TO_200', self.default_change_400_to_200): code = 200 resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e headers = Headers() if isinstance(e, HTTPException): code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } headers = e.get_response().headers else: code = 500 default_data = { 'message': http_status_message(code), } # Werkzeug exceptions generate a content-length header which is added # to the response in addition to the actual content-length header # https://github.com/flask-restful/flask-restful/issues/534 remove_headers = ('Content-Length', ) for header in remove_headers: headers.pop(header, None) data = getattr(e, 'data', default_data) if code and code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[ 0] if supported_mediatypes else "text/plain" resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): got_request_exception.send(current_app._get_current_object(), exception=e) if not hasattr(e, 'code') and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e code = getattr(e, 'code', 500) data = getattr(e, 'data', error_data(code)) headers = {} if code >= 500: if sys.exc_info() == (None, None, None): current_app.logger.error("Internal Error") else: current_app.logger.exception("Internal Error") help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404 and ('message' not in data or data['message'] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] += ". " else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' if code == 405: headers['Allow'] = e.valid_methods error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype=fallback_mediatype, ) else: if code == 400 and current_app.config.get('CHANGE_400_TO_200', self.default_change_400_to_200): code = 200 resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e if isinstance(e, HTTPException): code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } else: code = 500 default_data = { 'message': http_status_message(code), } data = getattr(e, 'data', default_data) headers = {} if code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404: rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] = data["message"].rstrip('.') + '. ' else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' if code == 405: headers['Allow'] = e.valid_methods error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype = fallback_mediatype ) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e headers = Headers() if isinstance(e, HTTPException): if e.response is not None: # If HTTPException is initialized with a response, then return e.get_response(). # This prevents specified error response from being overridden. # eg. HTTPException(response=Response("Hello World")) resp = e.get_response() return resp code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } headers = e.get_response().headers else: code = 500 default_data = { 'message': http_status_message(code), } # Werkzeug exceptions generate a content-length header which is added # to the response in addition to the actual content-length header # https://github.com/flask-restful/flask-restful/issues/534 remove_headers = ('Content-Length',) for header in remove_headers: headers.pop(header, None) data = getattr(e, 'data', default_data) if code and code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype = fallback_mediatype ) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp