The default message for Flask 400
exception (abort()
) is:
{
"message": "The browser (or proxy) sent a request that this server could not understand."
}
For 404
:
{
"message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. You have requested this URI [/obj/] but did you mean /obj/ or /obj/<int:id>/ or /obj/<int:id>/kill/ ?"
}
I have trouble comprehending these messages when I'm getting them as replies in my API (especially the first one, I thought there's something wrong with encryption or headers) and I thing it's kinda tiresome to try to override text manually for every abort()
exception. So I change the mapping:
from flask import abort
from werkzeug.exceptions import HTTPException
class BadRequest(HTTPException):
code = 400
description = 'Bad request.'
class NotFound(HTTPException):
code = 404
description = 'Resource not found.'
abort.mapping.update({
400: BadRequest,
404: NotFound
})
For the case of 400
it works beautifully. But when it comes to 404
it is still the same message. I tested it in the same place in my code - it works for abort(400)
, abort(403)
and some of the others, but it gets mysteriously overridden by default message on abort(404)
. Debugging didn't help much. What may be the culprit here?
Update. Yes, I'm using abort
imported from flask
not flask_restful
as the latter doesn't have the mapping and it's a function not an Aborter
object. Besides, it does work for most exceptions, so it's probably not the real issue here.
Update 2. The abort.mapping
seems to be perfectly fine on execution. The exceptions in question are overridden, including 404
.
Update 3: I've put together a little sandbox, that I use for debugging. (removed the repo since the mystery is long solved).
abort(...) raises itself an exception, one of the exceptions described in the docs, all subclasses of werkzeug. exceptions.
Flask comes with a handy abort() function that aborts a request with an HTTP error code early. It will also provide a plain black and white error page for you with a basic description, but nothing fancy. Depending on the error code it is less or more likely for the user to actually see such an error.
This can be done by registering error handlers. When Flask catches an exception while handling a request, it is first looked up by code. If no handler is registered for the code, Flask looks up the error by its class hierarchy; the most specific handler is chosen.
Make sure debug mode is off, then try again. Here is a comment directly from the code itself: Default exception handling that kicks in when an exception occurs that is not caught. In debug mode the exception will be re-raised immediately, otherwise it is logged and the handler for a 500 internal server error is used.
It took me some time, but now I actually found the place, where it all derails on 404
error. It's actually an undocumented feature in flask-restful. Look at the code here. Whatever message you chose persists until that very place and then it becomes the default. What we need now is just put ERROR_404_HELP = False
to our config and everything works as intended.
Why is this code even there in the first place? OK, perhaps, I can live with that, but it should be all over the documentation. Even when I googled the name of the constant, I only got a couple of GitHub issues (1, 2).
Anyways, the mystery is officially solved.
By the way... I can't point to documentation for how I discovered this, I just tried it (that's how I learn most development!) but, you can simply abort with the desired response code but instead return a custom string with it. I think this makes sense because you're using the framework the way it's intended, you're not writing tons of code, you're returning the correct response code and in the fashion the framework expects, and you're informing any human who reads it as to the application's context for the error.
from flask import abort
abort(404, "And here's why.")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With