Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to enable the toolbar to display on JSON responses? #89

Open
jeffwidman opened this issue Nov 19, 2015 · 9 comments
Open

Add option to enable the toolbar to display on JSON responses? #89

jeffwidman opened this issue Nov 19, 2015 · 9 comments

Comments

@jeffwidman
Copy link
Member

I am debugging a Flask app that serves up JSON for an API endpoint.

I'm viewing the JSON in the browser, and it'd be convenient to display the toolbar as well.

My understanding of content types is a little hazy... is it possible to add an option to display the toolbar alongside this JSON? Like perhaps a config setting that lets me turn on the toolbar for all responses, not just with <! doctype html>?

@sumoward
Copy link

Jef did you have any luck getting this done?

@jeffwidman
Copy link
Member Author

No. The way to do it I think, so you don't have to get funky with adding a HTML wrapper around the JSON is detect the content type and have the toolbar append its own bit of JSON with the sqlalchemy queries + page timing info, but thats still a pain methinks compared to just manually setting sqlalchemy to echo queries to stdout and watching your logs as you hit various endpoints.

@sumoward
Copy link

Thanks Jeff.

@sarimak
Copy link

sarimak commented Sep 6, 2016

Workaround:

@app.after_request
def after_request(response):
    # Wrap JSON responses by HTML and ask flask-debugtoolbar to inject own HTML into it
    if app.config.get("DEBUG_TB_ENABLED", False) and response.mimetype == "application/json" and response.status_code != 401:
        response.direct_passthrough = False  # Work-around for profiling of streamed JSON data download
        args = dict(response=response.data.decode("utf-8"), http_code=response.status)
        html_wrapped_response = make_response(render_template("wrap_json.html", **args), response.status_code)
        response = app.extensions["debugtoolbar"].process_response(html_wrapped_response)

    return response

and

<html>
    <head>
        <title>JSON Response</title>
    </head>

    <body>
        <h1>HTML Wrapper for JSON Response</h1>

        <h2>HTTP Code</h2>
        <pre>{{ http_code }}</pre>

        <h2>JSON Response</h2>
        <pre>{{ response }}</pre>
    </body>
</html>

@asldevi
Copy link

asldevi commented Oct 24, 2017

I also had to init the FDT like the following to make the above snippet work instead of just
DebugToolbarExtension(app)

    app.extensions = getattr(app, 'extensions', {})
    app.extensions['debugtoolbar'] = DebugToolbarExtension(app)

@guyecode
Copy link

guyecode commented Jan 17, 2018

@sarimak I add code exactly as yours, the toolbar show up on the page, but nothing pop up when click the menus.
I compared all the requests to the example in the source, there are two toolbar.css requests send to server, the rest requests are totally same.

@sarimak
Copy link

sarimak commented Feb 4, 2018

@guyecode You're right, FDT has changed since I posted the workaround. I can reproduce the issue (FDT for JSON response is displayed but ignores click events -- while it works fine for HTML response) with the following code:

import flask
import flask_debugtoolbar

app = flask.Flask('test', template_folder='.')
app.config['DEBUG_TB_ENABLED'] = True
app.config['SECRET_KEY'] = '123'
toolbar = flask_debugtoolbar.DebugToolbarExtension(app)

@app.after_request
def after_request(response):
    if response.mimetype == "application/json":
        html_wrapped_response = flask.make_response(flask.render_template("wrap_json.html", response=response.data.decode("utf-8"), http_code=response.status), response.status_code)
        return toolbar.process_response(html_wrapped_response)

    return response

@app.route('/json')
def test_json():
    return flask.jsonify(dict(key1='value1')), 200

@app.route('/html')
def test_html():
    return '<head/><body>test</body>', 200

if __name__ == '__main__':
    app.run(debug=True)

Unfortunately, I am not skilled enough in JavaScript to troubleshoot the issue.

@RealLiuSha
Copy link

RealLiuSha commented Feb 26, 2018

@sarimak

modify wrap_json.html to:

<html>
    <head>
        <title>JSON Response</title>
    </head>

    <body>
        <h1>HTML Wrapper for JSON Response</h1>

        <h2>HTTP Code</h2>
        <pre>{{ http_code }}</pre>

        <h2>JSON Response</h2>
        <pre>{{ response }}</pre>
    </body>

<script>
$('#flDebugPanelList').find('li a').click(function () {
    const current = $('#flDebug #' + this.className + '-content');
    if (current.is(':visible')) {
      $(document).trigger('close.flDebug');
      $(this).parent().removeClass('active');
    } else {
      $('.panelContent').hide();
      current.show();

      $('#flDebugToolbar').find('li').removeClass('active');
      $(this).parent().addClass('active');
    }
  });
</script>
</html>

image

@KyleJamesWalker
Copy link

I was also having issues with the click events not working with If you create the after_request before the toolbar extension it will see the html mimetype and work without needing future changes. Here's an extension I wrote for this in my app.

"""Flask Extensions"""
import flask
import flask_debugtoolbar

class DevToolbar:
    """Add debug toolbars with json to html

    Note you must pass `_debug` param to convert the json response
    """
    def __init__(self, app):
        wrap_json = """
        <html>
            <head>
                <title>Debugging JSON Response</title>
            </head>

            <body>
                <h1>Wrapped JSON Response</h1>

                <h2>HTTP Code</h2>
                <pre>{{ http_code }}</pre>

                <h2>JSON Response</h2>
                <pre>{{ response }}</pre>
            </body>
        </html>
        """

        @app.after_request
        def after_request(response):
            if response.mimetype == "application/json" and \
                '_debug' in flask.request.args:
                html_wrapped_response = flask.make_response(
                    flask.render_template_string(
                        wrap_json,
                        response=response.data.decode("utf-8"),
                        http_code=response.status
                    ),
                    response.status_code,
                )
                return app.process_response(html_wrapped_response)

            return response

        flask_debugtoolbar.DebugToolbarExtension(app)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

7 participants