Routing

You’ve probably noticed the other method inside our AccountDashboard handler: submit(). How do we use this?

Let’s look at another method on our RequestHandler: router():

@property
def router(self):
    router = super().router
    router.update({
        'default': self.default,
        'submit': self.submit
    })

    return router

This method is a computed property, as designated through use of the @property decorator built-in to Python. This means that the return value of this method can be accessed as a property of the RequestHandler through self.router.

router is just a simple mapping of a routing key to a method reference. This is how your RequestHandler knows which method should handle a particular request. This is how multi-step workflows are achieved, despite the fact that Caliper SDK extension is limited to a single form URL.

Your extension must always have a method called default(): this will handle the first request to your extension, before a routing key has been set.

In this case, the router will send a request to be handled by default() if the form is submitted with no key or with the routing key "default". If it receives a request with the routing key "submit", it will send the request to be handled by that method instead.

Note

Warning: the values in the dictionary returned by router are method references, not method calls. Adding parentheses after the method names in your router will cause errors.

Our next step will be to allow a user to enter an account ID in the input field on our form and be taken to a list showing that account’s recent transactions.

Lets take another look at the default() method:

async def default(self):
    account_models = []
    for account in self.account_list:
        account_models.append({
            'account_num': account.host_acct_id,
            'account_name': account.product_name,
            'account_balance': account.balance_to_display
        })

    template = self.get_template('index.html.jinja2', {
        'accounts': account_models
    })

    html = self.get_tecton_form(
        "AccountDashboard",
        custom_template=template,
        routing_key="submit"
    )
    return html

Remember, our input field has a name attribute. When we submit this form with something inside this field, self.form_fields will contain the key account_id (the name of the input) paired with a value, the user-submitted contents of that input.

Notice we are passing in a routing_key keyword argument: this will be stored in a hidden input on the rendered Q2Form and will be resubmitted along with that form. On submission, our router will read that key and call the method it maps to: self.submit().

Go ahead and try submitting the form now, and you’ll see that our default submit method was run:

async def submit(self):
    template = self.get_template(
        'submit.html.jinja2', {
            'header': "AccountDashboard",
            'message': 'Hello World POST: From "AccountDashboard".<br>',
            'data': format(self.form_fields.items())
        }
    )

    html = self.get_tecton_form(
        "AccountDashboard",
        custom_template=template,
        hide_submit_button=True
    )

    return html

The custom template simply prints out what you submitted in your form from the previous route.

We don’t pass a routing_key this time: there’s no form to submit here yet. Instead, we hide the inactive submit button via hide_submit_button=True.

Note

The routing_key keyword argument only affects the Q2Form default submit button. If your route isn’t displaying that, internal navigation is achieved via custom HTML, which will be demonstrated in a later step.

In the next step we’ll code our extension to fetch transaction history from HQ– the gateway into the Q2 database– using the HQ API.