1.. _guide.app:
2
3The WSGI application
4====================
5The WSGI application receives requests and dispatches the appropriate handler,
6returning a response to the client. It stores the URI routes that the app will
7accept, configuration variables and registered objects that can be shared
8between requests. The WSGI app is also responsible for handling uncaught
9exceptions, avoiding that stack traces "leak" to the client when in production.
10Let's take an in depth look at it now.
11
12.. note::
13   If the WSGI word looks totally unfamiliar to you, read the
14   `Another Do-It-Yourself Framework`_ tutorial by Ian Bicking. It is a very
15   recommended introduction to WSGI and you should at least take a quick look
16   at the concepts, but following the whole tutorial is really worth.
17
18   A more advanced reading is the WSGI specification described in the
19   `PEP 333 <http://www.python.org/dev/peps/pep-0333/>`_.
20
21
22Initialization
23--------------
24The :class:`webapp2.WSGIApplication` class is initialized with three optional
25arguments:
26
27- ``routes``: a list of route definitions as described in :ref:`guide.routing`.
28- ``debug``: a boolean flag that enables debug mode.
29- ``config``: a dictionary of configuration values for the application.
30
31Compared to webapp, only config was added; it is used as a standard way to
32configure extra modules (sessions, internationalization, templates or your
33own app configuration values).
34
35Everything is pretty straighforward::
36
37    import webapp2
38
39    routes = [
40        (r'/', 'handlers.HelloWorldHandler'),
41    ]
42
43    config = {}
44    config['webapp2_extras.sessions'] = {
45        'secret_key': 'something-very-very-secret',
46    }
47
48    app = webapp2.WSGIApplication(routes=routes, debug=True, config=config)
49
50
51.. _guide.app.router:
52
53Router
54------
55:ref:`guide.routing` is a central piece in webapp2, and its main component is
56the :class:`webapp2.Router` object, available in the application as the
57:attr:`webapp2.WSGIApplication.router` attribute.
58
59The router object is responsible for everything related to mapping URIs to
60handlers. The router:
61
62- Stores registered "routes", which map URIs to the application handlers
63  that will handle those requests.
64- Matches the current request against the registered routes and returns the
65  handler to be used for that request (or raises a ``HTTPNotFound`` exception
66  if no handler was found).
67- Dispatches the matched handler, i.e., calling it and returning a response
68  to the ``WSGIApplication``.
69- Builds URIs for the registered routes.
70
71Using the ``router`` attribute you can, for example, add new routes to the
72application after initialization using the ``add()`` method::
73
74    import webapp2
75
76    app = webapp2.WSGIApplication()
77    app.router.add((r'/', 'handlers.HelloWorldHandler'))
78
79The router has several methods to override how URIs are matched or built or how
80handlers are adapted or dispatched without even requiring subclassing. For an
81example of extending the default dispatching mechanism, see
82:ref:`Request handlers: returned values <guide.handlers.returned_values>`.
83
84Also check the :class:`Router API documentation <webapp2.Router>` for
85a description of the methods :meth:`webapp2.Router.set_matcher`,
86:meth:`webapp2.Router.set_dispatcher`, :meth:`webapp2.Router.set_adapter` and
87:meth:`webapp2.Router.set_builder`.
88
89
90.. _guide.app.config:
91
92Config
93------
94When instantiating the app, you can pass a configuration dictionary which is
95then accessible through the :attr:`webapp2.WSGIApplication.config` attribute.
96A convention is to define configuration keys for each module, to avoid name
97clashes, but you can define them as you wish, really, unless the module
98requires a specific setup. First you define a configuration::
99
100    import webapp2
101
102    config = {'foo': 'bar'}
103
104    app = webapp2.WSGIApplication(routes=[
105        (r'/', 'handlers.MyHandler'),
106    ], config=config)
107
108Then access it as you need. Inside a ``RequestHandler``, for example::
109
110    import webapp2
111
112    class MyHandler(webapp2.RequestHandler):
113        def get(self):
114            foo = self.app.config.get('foo')
115            self.response.write('foo value is %s' % foo)
116
117
118.. _guide.app.registry:
119
120Registry
121--------
122A simple dictionary is available in the application to register instances that
123are shared between requests: it is the :attr:`webapp2.WSGIApplication.registry`
124attribute. It can be used by anything that your app requires and the intention
125is to avoid global variables in modules, so that you can have multiple app
126instances using different configurations: each app has its own extra instances
127for any kind of object that is shared between requests. A simple example that
128registers a fictitious ``MyParser`` instance if it is not yet registered::
129
130    import webapp2
131
132    def get_parser():
133        app = webapp2.get_app()
134        # Check if the instance is already registered.
135        my_parser = app.registry.get('my_parser')
136        if not my_parser:
137            # Import the class lazily.
138            cls = webapp2.import_string('my.module.MyParser')
139            # Instantiate the imported class.
140            my_parser = cls()
141            # Register the instance in the registry.
142            app.registry['my_parser'] = my_parser
143
144        return my_parser
145
146The registry can be used to lazily instantiate objects when needed, and keep a
147reference in the application to be reused.
148
149A registry dictionary is also available in the
150:ref:`request object <guide.request.registry>`, to store shared objects
151used during a single request.
152
153
154Error handlers
155--------------
156As described in :ref:`guide.exceptions`, a dictionary is available in the app
157to register error handlers as the :attr:`webapp2.WSGIApplication.error_handlers`
158attribute. They will be used as a last resource if exceptions are not caught
159by handlers. It is a good idea to set at least error handlers for 404 and 500
160status codes::
161
162    import logging
163
164    import webapp2
165
166    def handle_404(request, response, exception):
167        logging.exception(exception)
168        response.write('Oops! I could swear this page was here!')
169        response.set_status(404)
170
171    def handle_500(request, response, exception):
172        logging.exception(exception)
173        response.write('A server error occurred!')
174        response.set_status(500)
175
176    app = webapp2.WSGIApplication([
177        webapp2.Route(r'/', handler='handlers.HomeHandler', name='home')
178    ])
179    app.error_handlers[404] = handle_404
180    app.error_handlers[500] = handle_500
181
182
183Debug flag
184----------
185A debug flag is passed to the WSGI application on instantiation and is
186available as the :attr:`webapp2.WSGIApplication.debug` attribute. When in
187debug mode, any exception that is now caught is raised and the stack trace is
188displayed to the client, which helps debugging. When not in debug mode, a
189'500 Internal Server Error' is displayed instead.
190
191You can use that flag to set special behaviors for the application during
192development.
193
194For App Engine, it is possible to detect if the code is running using the SDK
195or in production checking the 'SERVER_SOFTWARE' environ variable::
196
197    import os
198
199    import webapp2
200
201    debug = os.environ.get('SERVER_SOFTWARE', '').startswith('Dev')
202
203    app = webapp2.WSGIApplication(routes=[
204        (r'/', 'handlers.HelloWorldHandler'),
205    ], debug=debug)
206
207
208Thread-safe application
209-----------------------
210By default, webapp2 is thread-safe when the module
211:class:`webapp2_extras.local` is available. This means that it can be used
212outside of App Engine or in the upcoming App Engine Python 2.7 runtime.
213This also works in non-threaded environments such as App Engine Python 2.5.
214
215See in the :ref:`tutorials.quickstart.nogae` tutorial an explanation on how
216to use webapp2 outside of App Engine.
217
218
219Running the app
220---------------
221The application is executed in a CGI environment using the method
222:meth:`webapp2.WSGIApplication.run`. When using App Engine, it uses
223the functions ``run_bare_wsgi_app`` or ``run_wsgi_app`` from
224``google.appengine.ext.webapp.util``. Outside of App Engine, it uses the
225:py:mod:`wsgiref.handlers` module. Here's the simplest example::
226
227    import webapp2
228
229    class HelloWebapp2(webapp2.RequestHandler):
230        def get(self):
231            self.response.write('Hello, webapp2!')
232
233    app = webapp2.WSGIApplication([
234        ('/', HelloWebapp2),
235    ], debug=True)
236
237    def main():
238        app.run()
239
240    if __name__ == '__main__':
241        main()
242
243
244Unit testing
245------------
246As described in :ref:`guide.testing`, the application has a convenience method
247to test handlers: :meth:`webapp2.WSGIApplication.get_response`. It
248receives the same parameters as ``Request.blank()`` to build a request and call
249the application, returning the resulting response from a handler::
250
251    class HelloHandler(webapp2.RequestHandler):
252        def get(self):
253            self.response.write('Hello, world!')
254
255    app = webapp2.WSGIapplication([('/', HelloHandler)])
256
257    # Test the app, passing parameters to build a request.
258    response = app.get_response('/')
259    assert response.status_int == 200
260    assert response.body == 'Hello, world!'
261
262
263Getting the current app
264-----------------------
265The active ``WSGIApplication`` instance can be accessed at any place of your
266app using the function :func:`webapp2.get_app`. This is useful, for example, to
267access the app registry or configuration values::
268
269    import webapp2
270
271    app = webapp2.get_app()
272    config_value = app.config.get('my-config-key')
273
274
275.. _Another Do-It-Yourself Framework: http://docs.webob.org/en/latest/do-it-yourself.html
276