The WSGI Application

When you create an application using the nagare-admin create-app command (see Create an application for more details), Nagare automatically creates a class which acts as the root component of your application:

setup(
      ...
      entry_points = """
      [nagare.applications]
      myapp = myapp.app:app
      """
      ...
)
class Root(object):
    # root component of the application
    pass

@presentation.render_for(Root)
def render(self, h, *args):
    # some rendering code...
    return h.root

app = Root

Under the hood, Nagare automatically wraps this root component in a nagare.wsgi.WSGIApp instance via the nagare.wsgi.create_WSGIApp function). The WSGIApp is the plumbing between the WSGI protocol and Nagare’s component API (nagare.component): it exposes a WSGI interface to the host server (i.e. a publisher in Nagare terms) and maps the incoming requests to components updates and rendering. So, in short, the WSGIApp implements the WSGI application that serves your Nagare components as Web pages.

The WSGIApp provides some smart defaults for the common use-cases: there’s no authentication by default, a default locale is used so that localizable strings are returned as is, the exceptions that occur while processing your components are hidden behind a HTTP Internal Server Error, etc.

However, sometimes, you want to override this default application behavior: for example, you may want to use a user authentication scheme, show custom error pages when exceptions occur, initialize something in each request, change the locale, … We are going to show you how to do that, but we must first explain how Nagare handles a client request so that you can understand how to customize the application behavior.

How Nagare handles a client request

When the WSGI server receives a client request, it calls the nagare.wsgi.WSGIApp.__call__ method of the application, which returns the content of the response for this request, as described in the WSGI protocol. This is where Nagare does all the work so that your components are served as a Web pages on top of WSGI.

First, Nagare analyzes the incoming request in order to retrieve the session information (i.e. which user is sending the request to the server), and (eventually) the action the user triggered on the last page he visited.

The session information is represented by the _s and _c parameters of the URL. If the session information is either missing, expired or invalid, Nagare creates a new session and sets up the initial state of the application by calling the root component factory (i.e. the function passed to the WSGIApp constructor). This factory returns an instance of the root component that, once rendered, will be the first page the user will see. Otherwise, Nagare uses the session information to load the corresponding session data and initializes the components state from this data, which effectively put the components in the same setup as in the previous page.

When significative URLs are used (see Significative “RESTful” URLs), the URL is used to initialize the state of the components when a new session is created and is ignored otherwise (because the session data carries more state information than the URL itself).

Once the components are initialized, Nagare finds and executes the action callback (represented by the _actionNNN parameter of the URL, where NNN is a random number) which updates the state of the components to reflect the consequences of the action (see Callbacks and forms for more information about actions). This is the callback processing phase.

Finally, Nagare creates a renderer and renders the components tree starting from the root component. This is the rendering phase. At this point, we are not supposed to change the component graph, but it’s possible nevertheless.

After the rendering, the state of the components is persisted in the session store, which is either in memory, in memcache, or not at all, depending on the publisher configuration (see The publisher configuration file). The session stored can then be used in the next request to initialize the components before executing the action callback.

The same principles applies when your components are rendered asynchronously (i.e. with an AsyncRenderer), except that only a components subtree is rendered (starting from the asynchronous root) and the same session state is written over and over instead of creating a new state for each request as in synchronous mode.

To sum up, there are 4 important steps when handling a request:

  1. initialize the components from the session or from the URL (if a new session begins)
  2. update the components tree by processing the action callbacks
  3. render the components tree
  4. save the new state in the session

That’s basically what the WSGIApp.__call__ method does. However, note that there are many hooks called in this method that can be overridden to customize the application behavior. That’s what we’re going to review now.

Customizing the WSGIApp

It’s possible to customize the WSGIApp behavior by subclassing the WSGIApp class and changing the global app attribute to refer to the WSGIApp subclass, as shown below:

from nagare import wsgi

...

class MyApp(wsgi.WSGIApp):
    # put your customization code here
    pass

def root_factory():
    return component.Component(Root())

app = MyApp(root_factory)

The WSGIApp constructor accepts a root component factory as single argument, which is used to create the root component when a new session begins, that is, the initial state of the application when a new user comes in.

There are many methods that can be overridden in the WSGIApp. Maybe the most important one is WSGIApp.__call__ which has already been described: it implements the WSGI protocol. Most of the time, you don’t need to override this method directly because Nagare provides finer grained methods.

The nagare.wsgi.WSGIApp.start_request method is called at the begin of each incoming request. This is where we can perform reques or session specific initializations such as installing the locale depending on the user/browser settings, authenticating the user using the credentials sent in the request, initializing request or session scoped data… The first parameter of this method receives the root component that has just been created or been initialized from the session, before URL rules are process (i.e. presentation.init rules). The last two parameters are the request and the response objects.

The nagare.wsgi.WSGIApp.set_config method is another commonly used method: it’s the place where the application receives its configuration. You can read custom configuration sections and values in this method in order to configure the services that you use in your application.

For completeness, here is the full listing of the overridable methods and their purpose:

Method Purpose
__init__(root_factory) Constructor, receives the root component factory
__call__(environ, start_response) Implements the WSGI protocol. This is the plumbing between WSGI and the Nagare components
_phase1(request, response, callbacks) Phase 1: processes action callbacks in order to update the components tree
_phase2(output, content_type, doctype, is_xhr, response) Phase 2: renders the components tree
create_renderer(async, session, request, response, callbacks) Creates a renderer that will be used to render the components tree. Internally, it calls the WSGIApp.renderer_factory attribute to create the renderer, which is initialized by default to xhtml.Renderer. So, by default, Nagare uses a (X)HTML renderer to render the component
create_root(*args, **kw) Creates the application root component by using the component factory passed to the constructor. You can pass parameters to the root component in this method, such as instances of services initialized from the application configuration
on_after_post(request, response, ids) Generate a redirection after a POST request if the redirect_after_post option is enabled in the application configuration. It’s also known as the PRG Pattern
on_back(request, response, h, output) Called when the user used the back button of his browser
on_bad_http_method(request, response) Called when a HTTP request other than a GET or PUT was received. By default, this method returns a MethodNotAllowed response
on_callback_lookuperror(request, response, async) A callback was not found: this generally occurs when you use an asynchronous renderer to update a component on a page but try to use a (dead) callback (i.e. _actionNNN) defined in an older state of the component
on_exception(request, response) Method called when an unhandled exception occurs. Note that it does not include the exceptions deriving from webob.exc.HTTPException which are used to send special HTTP responses
on_incomplete_url(request, response) An URL without an application name was received
on_session_expired(request, response) The session information received is either expired or invalid
set_config(config_filename, config, error) Called when Nagare configures the application from the application configuration file. You can read you own configuration keys/values in this method
set_data_path(data_path) Register the directory where the application data is to be found
set_databases(databases) Register the databases properties
set_default_locale(locale) Register the default locale, i.e. the locale used by default in all requests
set_locale(locale) Set the locale for the current request
set_project(name) Register the application distribution name
set_publisher(publisher) Register the publisher that serves the application to the outside world (see The publisher configuration file)
set_sessions_manager(sessions_manager) Register the sessions manager (see The publisher configuration file)
set_static_path(static_path) Register the directory of the static contents of the application, such as Javascript or CSS files
set_static_url(static_url) Register the URL of the static contents
start() Called when the publisher starts a new process serving the application. May be useful to initialize process scoped data.
start_request(root, request, response) Called when a new request is received. This method can be used to access the request data, add some headers in the response or configure the root component that has just been deserialized from the session

Some examples

In order to illustrate how to use the WSGIApp methods, here are some examples showing how to solve common use-cases in Nagare applications.

Reading a specific configuration section to initialize a service

Imagine that you want to send emails to the visitors of your next Web application. So you need to be able to configure the host and the port of the SMTP server your Web application will connect to.

In the application configuration file, we can add a specific section that provides the configuration information for the mail sender service.

[mail]
host = mail.server.com
port = 25

In order to read this configuration section, we need to override the WSGIApp.set_config method.

import configobj
from nagare import wsgi, config
from myapp.mailsender import MailSender

class MyApp(wsgi.WSGIApp):
    APPLICATION_SPEC = {
        'mail': {
            'host': 'string(default="localhost")',
            'port': 'integer(default=25)',
        },
    }

    def set_config(self, config_filename, conf, error):
        # Call the base implementation
        super(MyApp, self).set_config(config_filename, conf, error)

        # Parse and convert the SMTP parameters
        conf = configobj.ConfigObj(conf, configspec=configobj.ConfigObj(self.APPLICATION_SPEC))
        config.validate(config_filename, conf, error)

        # Create the mail sender service instance
        mail_host = conf['mail']['host']
        mail_port = conf['mail']['port']
        self.mail_sender = MailSender(mail_host, mail_port)

    ...

First, we validate and read the configuration file, then we get the host and port values needed to configure our MailSender service. When creating the ConfigObj object, we use a configspec to:

  1. validate the correctness of the configuration file
  2. provide “smart” default values for the missing configuration keys
  3. convert the keys to the proper type

Now that the mail sender service is created, we must pass it to the Nagare components that need it. The configured mail sender instance can be passed to the root component by overriding the WSGIApp.create_root method:

class MyApp(wsgi.WSGIApp):
    ...

    def create_root(self, *args, **kw):
        return super(MyApp, self).create_root(self.mail_sender)

Then the root component can use the mail sender instance or pass it to its children components:

class Root(object):
    def __init__(self, mail_sender)
        self.mail_sender = mail_sender
        # Do something useful with the mail_sender:
        # use it in an action callback or pass it to a children component

def root_factory(mail_sender):
    return component.Component(Root(mail_sender))

app = MyApp(root_factory)

Authenticating users

Nagare applications have no user authentification by default, so all visitors are allowed to see your application. This default behavior is installed in the WSGIApp constructor. You can change it by creating a custom security manager using one of the authentification schemes available in the nagare.security package (such as a HTTP Basic authentication or a Form authentication retrieving users from a database).

Then, the custom security manager can be installed either in WSGIApp.__init__, WSGIApp.set_config or WSGIApp.start_request. Here is an example:

from myapp.security import MySecurityManager

class MyApp(wsgi.WSGIApp):
    def __init__(self, root_factory):
         super(MyApp, self).__init__(root_factory)
         self.security = MySecurityManager()

Installing a locale in each request

Basically, you can change the default locale globally by calling WSGIApp.set_default_locale, or just change the locale for the current request by calling WSGIApp.set_locale (according to a user or session locale setting for example). Some examples can be found in Internationalization of applications.

Serving an application in /

By default, an application named myapp is served in /myapp, but you may want your application to respond in the root URL (i.e. /) too. To achieve that, you must tell the publisher that your application must be registered to the root URL. This can be done by overriding the WSGIApp.set_publisher method:

class MyApp(wsgi.WSGIApp):
    def set_publisher(self, publisher):
        # Call the base implementation
        super(EurekaBase, self).set_publisher(publisher)

        # Register the application in the root URL
        publisher.register_application(self.application_path, '', self, self)

Note that the static contents of the application are still be served in /static/myapp.

Logging unhandled exceptions

We can intercept unhandled exceptions and log them to the application logger by overriding the WSGIApp.on_exception method, as show in the example below:

from nagare import log

class MyApp(wsgi.WSGIApp):
    def on_exception(self, request, response):
        # Log the current exception (i.e. sys.exc_info())
        log.exception('An error occured')

        # Return an internal server error to the client
        return webob.exc.HTTPInternalServerError()