API in Flask--returns JSON but HTML exceptions break my JSON client

14,519

Solution 1

You should define HTTP error handlers in flask.

A simple JSON returing 404 handler might look something like this:

@app.errorhandler(404)
def page_not_found(e):
    return flask.jsonify(error=404, text=str(e)), 404

With this you will be able to check for data.error on the client and if it exists you can get the error text with data.text (the error passed as e is werkzeug.exceptions.NotFound whose string representation is "404: Not Found").

Solution 2

Making the traceback available to the JSON client has the potential to disclose sensitive information.

My advice is:

  • turn debug off
  • install a log aggregation tool like sentry
  • make the error 500 page for this application return a generic error in json format

The 500 page could look like:

{ "error": "500 - internal server error" }

Solution 3

The code below should do the trick. So the idea is to catch any exception that might have been raised, get the exception details formatted as a string using the traceback module and then return that as valid json. I would recommend putting a bunch of except statements with the main types of errors you expect to happen and a more readable error message. Then you can have one last except as a catch all in case something strange and unexpected happens.

import traceback

@app.route('/route1')
def api_route1():
    if user_id in request.args: 
        try:
            k1 = request.args['user_id']
            return flask.jsonify(recs=some_function(k1))
        except:
            return flask.jsonify(exception=traceback.format_exc())
    else:
        return flask.jsonify(exception="no valid user_id supplied")
Share:
14,519
Deepak Mathpal
Author by

Deepak Mathpal

i build Systems & Tools for Analysis, Prediction, Visualization, & Simulation. i also design, code, and deploy complete distributed and (horizontally) scalable Machine Learning-based applications (e.g., anti-fraud filter, recommendation engine, monitoring/anomaly detectors), often in the service layer decoupled from the main app. Techniques: Machine Learning decision tree (CART/C4.5) & random forest deep learning (multi-layer perceptron) support vector machine (SVM/SVR) kNN/kdtree probabilistic graphical models (eg, Bayesian Net, Markov Random Field) - ***Dimension Reduction Techniques*** - spectral decomposition (PCA & kPCA, kLDA) - Kohonen Map (self-organizing map) - ***ETL pipelines*** - akka stream - Apache Spark - Kafka/Zookeeper - ***Social Network Analysis & Visualization*** - using graph theoretic techniques for - community detection - identify members essential for network health/growth - identify nascent sub-communities - particular fluency in *NetworkX*, *GraphViz* - ***Analysis & Modeling of Time Series*** - decomposition - forecasting - anomaly detection - ***Optimization*** - combinatorial optimization - csp - ***Numerical Methods*** - matrix decomposition - monte carlo techniques - Gaussian quadrature, - finite difference methods - ***Persistence*** - redis - postgres - ***Geo-Spatial Data Modeling, Persistence, & Computation*** - postgis (storage, query, computation) toolchain: scala apache spark apache kafka akka & akka-stream R python NumPy + SciPy + Matplotlib + pandas git (& gitHub) travis ci no recruiters

Updated on June 05, 2022

Comments

  • Deepak Mathpal
    Deepak Mathpal almost 2 years

    exceptions returned in HTML break my JSON client. I want to jsonify this output.

    More detail: i have a view function which an endpoint of this api app.

    As you can see, this function returns the result in json.

    @app.route('/route1')
    def api_route1():
        if user_id in request.args: 
            k1 = request.args['user_id']
            return flask.jsonify(recs=some_function(k1))
        else:
            return "no valid user_id supplied"
    

    The problem, unhandled exception are in HTML, e.g.,

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 
        Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
        <head>
            <title>TypeError: 'NoneType' object is not iterable // Werkzeug Debugger</title>
            <link rel="stylesheet" 
                href="?__debugger__=yes&amp;cmd=resource&amp;f=style.css" 
                type="text/css">
    

    This breaks my json client. The HTML format is clearly a default, but i don't know how to opt out of it and specify jsonified exceptions (and ideally jsonify anything returned even headers).

    I suspect what i need is somewhere in the excellent Flask documentation, but i can't find it.

  • sberry
    sberry over 11 years
    This is what the OP should do.
  • Anurag
    Anurag over 11 years
    even the else part can have jsonify, this will again return html when user_id is not in arguments.
  • Marwan Alsabbagh
    Marwan Alsabbagh over 11 years
    @Codeanu good suggestion, I updated the answer with what you suggested.
  • Michael
    Michael almost 2 years
    Does this mean I need to create an error handler per non-success http status code (5xx and 4xx)? There must be a better way.