From f2c688c3e89c88c1a99b33073372fea520d98a1b Mon Sep 17 00:00:00 2001 From: VivianDee <115420678+VivianDee@users.noreply.github.com> Date: Fri, 21 Mar 2025 11:18:03 +0100 Subject: [PATCH] [add]: Error handling --- app.log | 1 + app/__init__.py | 7 +++++++ app/config.py | 2 +- app/errors/__init__.py | 1 + app/errors/handlers.py | 11 ++++++++++ app/helpers/response_helper.py | 38 +++++++++++++++++++++++++++++++++- app/routes/routes.py | 1 + 7 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 app/errors/__init__.py create mode 100644 app/errors/handlers.py diff --git a/app.log b/app.log index ef7a054..a1fc158 100644 --- a/app.log +++ b/app.log @@ -131,3 +131,4 @@ TypeError: require_api_key() missing 1 required positional argument: 'f' 2025-03-21 09:41:13,582 - ERROR - Unauthorized access: Missing App-ID. 2025-03-21 09:41:16,993 - INFO - Processing Disbursement request 2025-03-21 09:41:16,995 - ERROR - Validation Error: {'requestId': ['Missing data for required field.'], 'productId': ['Missing data for required field.'], 'collectAmountMgtFee': ['Missing data for required field.'], 'collectAmountVAT': ['Missing data for required field.'], 'provideAmount': ['Missing data for required field.'], 'countryId': ['Missing data for required field.'], 'debtId': ['Missing data for required field.'], 'collectAmountInsurance': ['Missing data for required field.'], 'channel': ['Unknown field.'], 'lienAmount': ['Unknown field.'], '$type': ['Unknown field.'], 'msisdn': ['Unknown field.'], 'countryCode': ['Unknown field.']} +2025-03-21 09:48:19,845 - ERROR - Unauthorized access: Missing API key. diff --git a/app/__init__.py b/app/__init__.py index 179b2a7..2897066 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -2,6 +2,7 @@ from flask import Flask from flask_cors import CORS from app.config import Config from app.routes import api +from app.errors import bad_request, method_not_allowed, not_found def create_app(): """ Factory function to create a Flask app instance """ @@ -16,4 +17,10 @@ def create_app(): # Register blueprints app.register_blueprint(api) + + # Error Handlers + app.register_error_handler(400, bad_request) + app.register_error_handler(404, not_found) + app.register_error_handler(405, method_not_allowed) + return app diff --git a/app/config.py b/app/config.py index 5e16347..6d1ea9c 100644 --- a/app/config.py +++ b/app/config.py @@ -3,7 +3,7 @@ import os class Config: """Base configuration for Flask app""" - # SQLALCHEMY_DATABASE_URI = "mysql://root:password@localhost/flask_app" + # SQLALCHEMY_DATABASE_URI =os.environ.get("DATABASE_URL", "database_url") # SQLALCHEMY_TRACK_MODIFICATIONS = False # SECRET_KEY = os.environ.get("SECRET_KEY", "your_secret_key") diff --git a/app/errors/__init__.py b/app/errors/__init__.py new file mode 100644 index 0000000..77d4ccc --- /dev/null +++ b/app/errors/__init__.py @@ -0,0 +1 @@ +from .handlers import bad_request, method_not_allowed, not_found \ No newline at end of file diff --git a/app/errors/handlers.py b/app/errors/handlers.py new file mode 100644 index 0000000..74c4608 --- /dev/null +++ b/app/errors/handlers.py @@ -0,0 +1,11 @@ +from flask import jsonify +from app.helpers.response_helper import ResponseHelper + +def method_not_allowed(error): + return ResponseHelper.method_not_allowed(message="Method Not Allowed") + +def not_found(error): + return ResponseHelper.not_found(message="URL Not Found") + +def bad_request(error): + return ResponseHelper.bad_request(message="Bad Request") diff --git a/app/helpers/response_helper.py b/app/helpers/response_helper.py index 3fd729d..17f35b7 100644 --- a/app/helpers/response_helper.py +++ b/app/helpers/response_helper.py @@ -212,4 +212,40 @@ class ResponseHelper: """ return ResponseHelper.build_response(False, message, data, 422, error) - \ No newline at end of file + @staticmethod + def method_not_allowed( + message: str = "Method Not Allowed", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for a method not allowed error. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 405, error) + + @staticmethod + def bad_request( + message: str = "Bad Request", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for a bad request error. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 400, error) \ No newline at end of file diff --git a/app/routes/routes.py b/app/routes/routes.py index 86df5e2..e4ee964 100644 --- a/app/routes/routes.py +++ b/app/routes/routes.py @@ -18,6 +18,7 @@ from app.middlewares import require_app_id api = Blueprint("api", __name__) + # @api.before_request # def require_api_key_middleware(): # """Middleware applied globally to all API routes in this blueprint"""