Chris Edwards
Chris Edwards

Reputation: 1558

Flask returning 404 triggers exception block and doesnt return Not Found

I have a very very simple flask server just for learning purposes but what I don't understand is when i return abort(404) it triggers the exception block and doesn't actually return the 404 it actually returns:

HI 2017-02-16 18:46:27,048 - __main__ - ERROR - Exception on /dddd [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.5/site-packages/flask/app.py", line 1478, in full_dispatch_request
    response = self.make_response(rv)
  File "/usr/local/lib/python3.5/site-packages/flask/app.py", line 1566, in make_response
    raise ValueError('View function did not return a response')
ValueError: View function did not return a response

Flask server code:

from flask import Flask, request, redirect, jsonify, abort, Response

@application.route("/<short_link>", methods=['GET'])
def get_short_link(short_link):
    try:
        if id_exists(short_link):
            return redirect(find_full_link_by_id(short_link), code=302)
        return abort(404)
    except:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        print("SOME PLACEHOLDER")

if __name__ == '__main__':
    application.run()

where id_exists queries a MySql database, this all works I have tested this in segregation.

My understanding would be that having this:

if id_exists(short_link):
            return redirect(find_full_link_by_id(short_link), code=302)
return abort(404)

it should always return.

Also my server has a post endpoint which returns a 415 if you don't use application/json as the content type. This works as expected:

try:
    if request.headers['Content-Type'] == 'application/json':
        full_link = request.get_json(force=True).get('fullLink')
        return jsonify(shortLink=generate(full_link, 5), fullLink=full_link)
    return abort(Response('Unsupported Media Type', 415))
except:
    # Some error handling omitted for this purpose

which does correctly return the 415 response. I have tried returning 200, 415, 403 etc just to see if its something special about the 404 but no look.

What am I doing wrong? I'm new to this framework.

EDIT: Just to clarify if I use a debugging tool and update my code to be:

 try:
        if id_exists(short_link):
            return redirect(find_full_link_by_id(short_link), code=302)
        return abort(404)
 except Exception as e:
     #do something... removed for the sake of clarity

the debugging says the exception (e) is actually 404: Not Found using PyCharm IDE

Upvotes: 2

Views: 6708

Answers (1)

Wombatz
Wombatz

Reputation: 5449

abort() is a non returning function. It doesn't return because the only thing it does is raise an exception. So the first mistake you are makeing is return abort(...). The return is never reached.

The second mistake is the try except statement.

  1. This is a good example why a bare except is bad. Don't do that unless you know for sure that you need it.

  2. You explicitly raise an exception and catch that in the except block. Why raise in the first place if you catch it directly?

To solve your problem use this pattern:

if object_not_found:
    abort(404)
do_something
return your_response

Note: it's just abort without return.

Always make sure your view does return a response.

Your code didn't work because you caught the abort exception in your except block and you didn't return a response after that.

Upvotes: 6

Related Questions