34
from yourapplication import create_app
app = create_app(/path/to/config.cfg)
app.run()
18.2.3 Factory Improvements
The factory function from above is not very clever so far, you can improve it. The
following changes are straightforward and possible:
1. make it possible to pass in configuration values for unittests so that you don’t
have to create config files on the filesystem
2. call a function from a blueprint when the application is setting up so that you
have a place to modify attributes of the application (like hooking in before /
after request handlers etc.)
3. Add in WSGI middlewares when the application is creating if necessary.
18.3 Application Dispatching
Application dispatching is the process of combining multiple Flask applications on
the WSGI level. You can not only combine Flask applications into something larger
but any WSGI application. This would even allow you to run a Django and a Flask
application in the same interpreter side by side if you want. The usefulness of this
depends on how the applications work internally.
The fundamental difference from the module approach is that in this case you are run-
ning the same or different Flask applications thatare entirely isolated from each other.
They run different configurations and are dispatched on the WSGI level.
18.3.1 Working with this Document
Each of the techniques and examples below results in an application object that
can be run with any WSGI server. For production, see Deployment Options. For
development, Werkzeug provides a builtin server for development available at
werkzeug.serving.run_simple():
from werkzeug.serving import run_simple
run_simple(localhost, 5000, application, use_reloader=True)
Note thatrun_simple is not intended for use in production. Use a full-blown WSGI
server.
In order to use the interactive debuggger, debugging must be enabled both on the
application and the simple server, here is the “hello world” example with debugging
andrun_simple:
105
38
from flask import Flask
from werkzeug.serving import run_simple
app = Flask(__name__)
app.debug = True
@app.route(/)
def hello_world():
return Hello World!
if __name__ == __main__:
run_simple(localhost, 5000, app,
use_reloader=True, use_debugger=True, use_evalex=True)
18.3.2 Combining Applications
If you have entirely separated applications and you want them to work next to
each other in the same Python interpreter process you can take advantage of the
werkzeug.wsgi.DispatcherMiddleware. Theideahereisthat t eachFlaskapplication
is a valid WSGI application and they are combined by the dispatcher middleware into
alarger one that dispatched based on prefix.
For example you could have your main application run on / and your backend inter-
face on /backend:
from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as s frontend
from backend_app import application as backend
application = DispatcherMiddleware(frontend, {
/backend:
backend
})
18.3.3 Dispatch by Subdomain
Sometimes you might want to use multiple instances of the same application with
different configurations. Assuming the application is created inside a function and
you can call that function to instantiate it, that is really easy to implement. In order to
develop your application to support creating new instances in functions have a look
at the Application Factories pattern.
Avery common example would be creating applications per subdomain. For instance
you configure your webserver to dispatch all requests for all subdomains to your
application and you then use the subdomain information to create user-specific in-
stances. Once you have your server set up to listen on all subdomains you can use a
very simple WSGI application to do the dynamic application creation.
The perfect level for abstraction in that regard is the WSGI layer. You write your own
106
39
WSGI application that looks at the request that comes and delegates it to your Flask
application. If that application does notexist yet, itis dynamically created and remem-
bered:
from threading import t Lock
class SubdomainDispatcher(object):
def __init__(self, domain, , create_app):
self.domain = domain
self.create_app = create_app
self.lock = Lock()
self.instances = {}
def get_application(self, host):
host = host.split(:)[0]
assert host.endswith(self.domain), Configuration error
subdomain = host[:-len(self.domain)].rstrip(.)
with self.lock:
app = self.instances.get(subdomain)
if app is None:
app = self.create_app(subdomain)
self.instances[subdomain] = app
return app
def __call__(self, environ, , start_response):
app = self.get_application(environ[HTTP_HOST])
return app(environ, start_response)
This dispatcher can then be used like this:
from myapplication import create_app, get_user_for_subdomain
from werkzeug.exceptions import NotFound
def make_app(subdomain):
user = get_user_for_subdomain(subdomain)
if user is None:
# if there is no user for that subdomain we still have
# to return a WSGI application that handles that request.
# We can then just return the NotFound() exception as
# application which will render a default 404 page.
# You might also redirect the user to the main page then
return NotFound()
# otherwise create the application for the specific user
return create_app(user)
application = SubdomainDispatcher(example.com, make_app)
107
38
18.3.4 Dispatch by Path
Dispatching by a path onthe URL is very similar. Instead of looking atthe Host header
to figure out the subdomain one simply looks at the request path up to the first slash:
from threading import t Lock
from werkzeug.wsgi import pop_path_info, peek_path_info
class PathDispatcher(object):
def __init__(self, default_app, , create_app):
self.default_app = default_app
self.create_app = create_app
self.lock = Lock()
self.instances = {}
def get_application(self, prefix):
with self.lock:
app = self.instances.get(prefix)
if app is None:
app = self.create_app(prefix)
if app is not None:
self.instances[prefix] = app
return app
def __call__(self, environ, , start_response):
app = self.get_application(peek_path_info(environ))
if app is not None:
pop_path_info(environ)
else:
app = self.default_app
return app(environ, start_response)
The big difference between this and the subdomain one is that this one falls back to
another application if the creator function returns None:
from myapplication import create_app, default_app, , get_user_for_prefix
def make_app(prefix):
user = get_user_for_prefix(prefix)
if user is not None:
return create_app(user)
application = PathDispatcher(default_app, make_app)
18.4 Implementing API Exceptions
It’s very common to implement RESTful APIs on top of Flask. One of the first thing
that developers run into is the realization that the builtin exceptions are not expressive
108
35
enough for APIs and that the content type of text/html they are emitting is not very
useful for API consumers.
The better solution than using abort to signal errors for invalid API usage is to im-
plement your own exception type and install an error handler for it that produces the
errors in the format the user is expecting.
18.4.1 Simple Exception Class
The basic idea is to introduce a new exception that can take a proper human readable
message, a status code for the error and some optional payload to give more context
for the error.
This is a simple example:
from flask import jsonify
class InvalidUsage(Exception):
status_code = 400
def __init__(self, message, , status_code=None, payload=None):
Exception.__init__(self)
self.message = message
if status_code is not None:
self.status_code = status_code
self.payload = payload
def to_dict(self):
rv = dict(self.payload d or ())
rv[message] = self.message
return rv
Aview can now raise that exception with an error message. Additionally some extra
payload can be provided as a dictionary through the payload parameter.
18.4.2 Registering an Error Handler
At that point views can raise that error, but it would immediately result in an internal
server error. The reason for this is that there is no handler registered for this error
class. That however is easy to add:
@app.errorhandler(InvalidAPIUsage)
def handle_invalid_usage(error):
response = jsonify(error.to_dict())
response.status_code = error.status_code
return response
109
34
18.4.3 Usage in Views
Here is how a view can use that functionality:
@app.route(/foo)
def get_foo():
raise InvalidUsage(This view w is gone, status_code=410)
18.5 Using URL Processors
New in version 0.7.
Flask 0.7 introduces the concept of URL processors. The idea is that you might have
abunch of resources with common parts in the URL that you don’t always explicitly
wantto provide. For instance you might have a bunch of URLs that have the language
code in it but you don’t want to have to handle it in every single function yourself.
URL processorsare especially helpful when combined withblueprints. We will handle
both application specific URL processors here as well as blueprint specifics.
18.5.1 Internationalized Application URLs
Consider an application like this:
from flask import Flask, g
app = Flask(__name__)
@app.route(/<lang_code>/)
def index(lang_code):
g.lang_code = lang_code
...
@app.route(/<lang_code>/about)
def about(lang_code):
g.lang_code = lang_code
...
This is an awful lot of repetition as you have to handle the language code setting on the
gobject yourself in every single function. Sure, a decorator could be used to simplify
this, but if you want to generate URLs from one function to another you would have
to still provide the language code explicitly which can be annoying.
For the latter, this is where url_defaults() functions come in. They can automatically
inject values into a call for url_for() automatically. The code below checks if the
language code is not yet in the dictionary of URL values and if the endpoint wants a
value named ’lang_code’:
110
Documents you may be interested
Documents you may be interested