1

I can't handle 400 BadRequest in my Flask app. Below is main.py:

from dotenv import find_dotenv, load_dotenv
from werkzeug.exceptions import BadRequest

from app import create_app, db
from app.orm import init_db, drop_db
from app.rest.core import InternalServerError, reply, handle_bad_request_error, BadRequestError

load_dotenv(find_dotenv())

app = create_app()


@app.errorhandler(BadRequest)
def handle_bad_request(ex):
    print(ex)
    return handle_bad_request_error(BadRequestError(ex.description))


@app.errorhandler
def handle_all(ex: Exception):
    print(ex)
    err = InternalServerError(description='')
    return reply(err)


@app.cli.command('initdb')
def init_db_command():
    init_db(db)


@app.cli.command('dropdb')
def drop_db_command():
    drop_db(db)


if __name__ == "__main__":
    # Print API map
    with app.app_context():
        # site_map(app)
        # Initialize DB
        init_db(db)
    # Run
    app.run()

I also tried to write 400 instead of BadRequest and handle it in Blueprint using @bp.errorahandler and @bp.app_errorhandler decorators. Flask just f****d all my attempts. I still get a standard error message:

{
    "message": {
        "Authorization": "Basic authorization required"
    }
}

Here is my Resource that throws this exception:

class AccessTokenResource(BaseResource):

    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('Authorization', required=True, location='headers', help='Basic authorization required')
        basic = parser.parse_args()['Authorization']
        if not basic or not basic.lower().startswith('basic '):
            raise UnauthorizedError('Basic authorization required')
        try:
            credentials = base64.b64decode(basic.split()[1]).decode('utf-8')
            email, password = credentials.split(':')
        except Exception as error:
            print(error)
            raise UnauthorizedError('Basic authorization required')
        user = self.db.get_user_by_email(email)
        if user is None or not user.check_password(password):
            raise InvalidEmailOrPasswordError()
        json = AccessTokenSchema().dump(AccessToken(user, app.config['SECRET_KEY']))
        return json, 200, {
            'Cache-Control': 'no-store',
            'Pragma': 'no-cache'
        }

I register resource as below:

bp = Blueprint('api', __name__)
api = Api(bp)

def init_app(app: Flask):
    schema.init_app(app)
    init_routes(api)
    app.register_blueprint(bp, url_prefix=app.config['API_ENDPOINT'])

Blueprint (bp) catches all exceptions but 400, so I moved it out to use app's decorator but it still doesn't work. Examples from official documentation didn't help too.

Where can problem be? What am I doing wrongly?

Denis Sologub
  • 7,277
  • 11
  • 56
  • 123
  • 1
    What is the exception you want to catch in your code ? If I understand, the one for UnauthorizedError is correctly catched by you BadRequest errorhandler. What is your API Rest framework ? Should have a look its documentation. To catch an exception, you can catch the one you will call using errorhandler on app or bp (depending if you want it on your global app or just your bp). You can also catch using a parent exception to catch all 400 exception, which is what you do with BadRequest – Pyglouthon Oct 31 '19 at 09:15
  • @Pyglouthon as I got I need to override `flask_restful.Api` class – Denis Sologub Oct 31 '19 at 09:22
  • You didn't answer to my questions. I don't understand what is wrong here. I mean, you do a request without the Authorization header so the API return an error with the proper message to alert you about the missing header. What part of the code is not catch by the error handler ? – Pyglouthon Oct 31 '19 at 09:27
  • @Pyglouthon, I need to change a format of error. I know why it throws exception (I do it specially). But I want to catch and wrap that exception. – Denis Sologub Oct 31 '19 at 09:30
  • Ok, I didn't understand that. So what is the format you would like ? – Pyglouthon Oct 31 '19 at 09:32
  • 1
    There is a workaround discussed [here](https://github.com/flask-restful/flask-restful/issues/280#issuecomment-329001383) – Pyglouthon Oct 31 '19 at 09:45
  • @Pyglouthon, thank you! I've overrided `Api.handle_error()`, it works. – Denis Sologub Oct 31 '19 at 09:53

0 Answers0