Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access the response object in a bottlepy after_request hook

Tags:

python

bottle

I have the following web app:

import bottle
app = bottle.Bottle()

@app.route('/ping')
def ping():
    print 'pong'
    return 'pong'

@app.hook('after_request')
def after():
    print 'foo'
    print bottle.response.body

if __name__ == "__main__":
    app.run(host='0.0.0.0', port='9999', server='cherrypy')

Is there a way to access the response body before sending the response back?

If I start the app and I query /ping, I can see in the console that the ping() and the after() function run in the right sequence

$ python bottle_after_request.py 
Bottle v0.11.6 server starting up (using CherryPyServer())...
Listening on http://0.0.0.0:9999/
Hit Ctrl-C to quit.

pong
foo

but when in after() I try to access response.body, I don't have anything.

In Flask the after_request decorated functions take in input the response object so it's easy to access it. How can I do the same in Bottle?

Is there something I'm missing?

like image 722
Giovanni Di Milia Avatar asked Feb 13 '14 22:02

Giovanni Di Milia


2 Answers

Is there a way to access the response body before sending the response back?

You could write a simple plugin, which (depending on what you're actually trying to do with the response) might be all you need.

Here's an example from the Bottle plugin docs, which sets a request header. It could just as easily manipulate body.

from bottle import response, install
import time

def stopwatch(callback):
    def wrapper(*args, **kwargs):
        start = time.time()
        body = callback(*args, **kwargs)
        end = time.time()
        response.headers['X-Exec-Time'] = str(end - start)
        return body
    return wrapper

install(stopwatch)

Hope that works for your purposes.

like image 61
ron rothman Avatar answered Sep 25 '22 00:09

ron rothman


You can use plugin approach, this is what i did

from bottle import response


class BottlePlugin(object):

    name = 'my_custom_plugin'
    api = 2

    def __init__(self, debug=False):
        self.debug = debug
        self.app = None

    def setup(self, app):
        """Handle plugin install"""
        self.app = app

    def apply(self, callback):
        """Handle route callbacks"""
        def wrapper(*a, **ka):
            """Encapsulate the result in the expected api structure"""
            # Check if the client wants a different format

            # output depends what you are returning from view
            # in my case its dict with keys ("data")
            output = callback(*a, **ka)
            data = output["data"]
            paging = output.get("paging", {})

            response_data = {
                data: data,
                paging: paging
            }
            # in case if you want to update response
            # e.g response code
            response.status = 200

            return response_data

        return wrapper
like image 25
Adeel Avatar answered Sep 27 '22 00:09

Adeel