Controllers

Watson provides two different types of controllers which are called Action and Rest respectively. Each one has its own uses and there is no one size fits all solution. A controller is only initialized once, and will not be initialized on each request. Due to this, you must not store any sort of state on the controller. Everything relating to the request the controller is currently dealing with can be retrieved by Controller.event.params[‘context’].

Creating controllers

Action controllers

Action controller methods are defined explicitly within the applications route configuration. In the following example, when a request is made to / then the app_name.controllers.Public controller is initialized, and the indexAction method is invoked.

app_name/config/config.py

routes = {
    'index': {
        'path': '/',
        'defaults': {'controller': 'app_name.controllers.Public', 'action': 'index'}
    },
}

app_name/controllers/__init__.py

from watson.framework import controllers

class Public(controllers.Action):
    def index_action(self):
        pass

RESTful controllers

RESTful controller methods are based upon the HTTP request method that was made by the user. In the following example, when a request is made to / the app_name.controllers.User controller is initialized, and the relevant HTTP request method is invoked.

app_name/config/config.py

routes = {
    'index': {
        'path': '/',
        'defaults': {'controller': 'app_name.controllers.User'}
    },
}

app_name/controllers/__init__.py

from watson.framework import controllers

class User(controllers.Rest):
    def GET(self):
        pass

    def POST(self):
        pass

    def PUT(self):
        pass

    def DELETE(self):
        pass

Common tasks

Accessing Request and Response objects

No changes should be made to the request object, and they should be treated as immutable. However any modifications can be made to the response object, as it will be used when the application renders the response to the user.

from watson.framework import controllers

class Controller(controllers.Rest):
    def GET(self):
        request = self.request  # the watson.http.messages.Request object
        response = self.response  # the watson.http.messages.Response object

For more information on request and response objects see the Reference Library.

Redirecting a request to another route or url

from watson.framework import controllers

class Controller(controllers.Rest):
    def GET(self):
        self.redirect('/')  # redirect the user to specific url

    def POST(self):
        self.redirect('home')  # redirect the user to a named route

For more information on the various arguments that can be passed to redirect() see the Reference Library.

When a user is redirected, any POST or PUT variables will be saved within the users session to solve the PRG (Post Redirect Get) issue. These variables may then be accessed to populate a form for example and are stored within the redirect_vars attribute of the controller. They can subsequently be cleared via the clear_redirect_vars() method on the controller.

Flash messaging

Flash messaging is a way to send messages between requests. For example, a user may submit some form data to be saved, at which point the application would

from watson.framework import controllers
from app_name import forms

class Controller(controllers.Rest):
    def GET(self):
        return {
            'form': forms.Login(),  # form has a POST method
        }

    def POST(self):
        form = forms.Login()
        form.data = self.request.post
        if form.is_valid():
            self.flash_messages.add('Successfully logged in', 'info')
        else:
            self.flash_messages.add('Invalid username or password', 'error')
        self.redirect('login')
<html>
    <head></head>
    <body>
        {% for namespace, message in get_flash_messages() %}
        <div class="{{ namespace }}">{{ message }}</div>
        {% endfor %}
        {{ form.open() }}
        {{ form.username.render_with_label() }}
        {{ form.password.render_with_label() }}
        {{ form.submit }}
        {{ form.close() }}
    </body>
</html>

Once flash messages have been iterated over, they are automatically cleared from the flash message container.

404 and other http errors

Raising 404 Not Found errors and other HTTP error codes are simple to do directly from the controller.

from watson.framework import controllers, exceptions

class Controller(controllers.Rest):
    def GET(self):
        raise exceptions.NotFoundError()

To raise a custom error code, you can raise an ApplicationError with a message and code specified.

from watson.framework import controllers, exceptions

class Controller(controllers.Rest):
    def GET(self):
        raise exceptions.ApplicationError('Some horrible error', status_code=418)