Extensions and middlewares

Flask extensions are simply Python projects that, once installed, provide a package or a module named flask_something. In previous versions, it was flask.ext.something.

The project has to follow a few guidelines, as described at http://flask.pocoo.org/docs/latest/extensiondev. These guidelines are more or less good practices that could apply to any Python project. Flask has a curated list of extensions maintained at http://flask.pocoo.org/extensions/, which is a good first stop when you are looking for extra features. What's provided by the extension is up to the developers, and not much is enforced besides the guidelines described in Flask documentation.

The other mechanism to extend Flask is to use WSGI middlewares. A WSGI middleware is a pattern to extend WSGI apps by wrapping the calls made to the WSGI endpoint.

In the example that follows, the middleware fakes a X-Forwarded-For header, so the Flask application thinks it's behind a proxy like nginx. This is a useful middleware in a testing environment when you want to make sure your application behaves properly when it tries to get the remote IP address, since the remote_addr attribute will get the IP of the proxy, not the real client:

    from flask import Flask, jsonify, request 
import json

class XFFMiddleware(object):
def __init__(self, app, real_ip='10.1.1.1'):
self.app = app
self.real_ip = real_ip

def __call__(self, environ, start_response):
if 'HTTP_X_FORWARDED_FOR' not in environ:
values = '%s, 10.3.4.5, 127.0.0.1' % self.real_ip
environ['HTTP_X_FORWARDED_FOR'] = values
return self.app(environ, start_response)

app = Flask(__name__)
app.wsgi_app = XFFMiddleware(app.wsgi_app)

@app.route('/api')
def my_microservice():
if "X-Forwarded-For" in request.headers:
ips = [ip.strip() for ip in
request.headers['X-Forwarded-For'].split(',')]
ip = ips[0]
else:
ip = request.remote_addr

return jsonify({'Hello': ip})

if __name__ == '__main__':
app.run()
Notice that we use app.wsgi_app here to wrap the WSGI app. In Flask, the app object is not the WSGI application itself as we've seen earlier.

Tampering with the WSGI environ before your application gets it is fine, but if you want to implement anything that will impact the response, doing it inside a WSGI middleware is going to make your work very painful.

The WSGI protocol requires that the start_response function gets called with the response status code, and headers before the app sends back the actual body content. Unfortunately, a single function call on your application triggers this two-step mechanism. So, changing the results on the fly from outside the app requires some callback magic to work.

A good example is when you want to modify the response body. That impacts the Content-Length header, so your middleware will need to intercept the headers sent by the app, and rewrite them after the body has been modified.

And this is just one problem of the WSGI protocol design; there are many other issues around it.

Unless you want your functionality to work for other WSGI frameworks, there are no good reasons to extend your apps with WSGI middlewares. It's much better to write a Flask extension that will interact from within the Flask application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset