4

I'm making a small web interface running on a raspberry pi at home. It hosts a little REST api as well as some web pages.

I'm using Flask, and have a route '/' for the index, and some routes for the REST api '/api/v1.0/tasks'.

@app.route('/') 
def index():
    return render_template('index.html')

@app.route('/gnodes/api/v1.0/tasks', methods=['GET'])
def get_tasks():
    return jsonify({'tasks': tasks})

@app.route('/gnodes/api/v1.0/tasks/<int:task_id>', methods=['GET'])
def get_task(task_id):
    task = [task for task in tasks if task['id'] == task_id]
    if not task:
        abort(404)
    return jsonify({'task': task[0]})

However, abort(404) returns a html error page, which is fine for normal pages, but I wanted to return a json when a non-existing task is requested.

So I've overridden the errorhandler:

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

However, now all error return the json, rather than only the api error.

So my question, how can I make failed requests to the API return the json error, but other errors the default html error page?

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
The Oddler
  • 6,314
  • 7
  • 51
  • 94
  • @cricket_007 oh, for the moment that's just a global variable, though that will later be replaced by some code looking for the tasks in a database. – The Oddler Jun 18 '17 at 18:16
  • make a custom decorator for handling failed api requests – Arpit Solanki Jun 18 '17 at 18:17
  • @TheOddler any way what is tasks or where is it defines does not matter in this context – Arpit Solanki Jun 18 '17 at 18:17
  • Okay, just making sure that wasn't the cause of the error – OneCricketeer Jun 18 '17 at 18:18
  • No no, I'm just trying out flask for the little project. I want to get an error, but I want missing pages to return a HTML page saying the page is missing, while missing tasks should return a json object. This way the api always returns a json object, and the page requests alwaus return pages. But I can only override all 404 errors, not specific ones. – The Oddler Jun 18 '17 at 18:20
  • Can't you just replace `abort(404)` with `return jsonify({'error': 'Not found'})`? – Stuart Jun 18 '17 at 18:23
  • @Stuart I thought the same thing, however then it doesn't have the correct error code. And then I have to write that everywhere, while `abort(404)` is just so nice and short. – The Oddler Jun 18 '17 at 18:26
  • 1
    I believe you can write `abort(404, 'Task not found')` and the 2nd argument will be passed as `error.description`. See https://stackoverflow.com/a/21301229/567595. Your error handler can then return json for 'Task not found' errors and a 404 page for all other errors. – Stuart Jun 18 '17 at 18:32

1 Answers1

1

The best way I found to fix this is using blueprints.

I put my API in it's own blueprint, and there I can define an errorhandler for that blueprint alone.

The only problem is that when there are non-existing pages in the api the default errorhandler is used, rather than the one I defined for the api-blueprint. There are some workaround for that too, but this is a limitation of Flask aparently, no biggy.

The Oddler
  • 6,314
  • 7
  • 51
  • 94