Skip to main content

Twisted Klein: Expanding Your App

Expanding Your App

Subroutes

Let’s start with a simple way to combine routes that share a common endpoint. For example, lets say we need routes for /base/first, /base/second, /base/third. The crude way of achieving this would be to explicitly write out each route with the /base route, like so:


app.route('/base/first')
def first(request):
    # ...

app.route('/base/second')
def second(request):
    # ...

app.route('/base/third')
def third(request):
    # ...

This is valid code, but there’s simpler syntax that can help reduce some common human errors like misspellings. The subroute function helps make the code more legible as well as simpler.

with app.subroute('/base') as sub:

    @sub.route('/first')
    def first(request):
        return 'first'

    @sub.route('/second')
    def second(request):
        return 'second'

    @sub.route('/third')
    def third(request):
        return 'third'

Expanding

It’s an inevitable fact that your application will grow and it may prove useful to import Klein objects from another module. Without going into great detail, Klein can handle nested routes by passing in branch=True in the route decorator, which allows then additional endpoints can be exposed. The route function should return Twisted a Resource object, which contain endpoints of their own. The actual implementation is much easier and less intimidating so please read on!

Static Files

Static files are a perfect way to illustrate how branching works. The following example will serve the files at a specific local directory.

from twisted.web.static import File

@app.route('/static', branch=True)
def static(request):
    return File('/path/to/static/files')

Notice the branch keyword in the route decorator. The branch syntax simply means there are other Resources (aptly labeled leaves) under this route. File objects return a Resource object for every file in the path.

Distributed Modules

Imagine the application you’ve built has grown large enough that placing all the routes in a single file has become too unwieldy. Expanding on the branch concept, we can generate the Resource file from other Klein objects, making it possible to simply import Klein objects.

blueprints.py

app = Klein()

@app.route('/hello')
def index(request):
    return 'Hello from the subroutes example'

with app.subroute('/blue') as sub:
    @sub.route('/first')
    def first(request):
        return 'first'

    @sub.route('/second')
    def second(request):
        return 'second'

    @sub.route('/third')
    def third(request):
        return 'third'

Now lets use this in another klein application.

from klein import Klein
from twisted.web.static import File

import blueprints    # this module holds the other Klein app

app = Klein()

@app.route('/branch', branch=True)
def branchOff(request):
    return blueprints.app.resource()        # get the Resource object

@app.route('/branch/2/', branch=True)
def branchAgain(request):
    return blueprints.app.resource()     # get the Resource object

For those who are familiar, this is similar to Flask and their concept of Blueprints. In my personal opinion, I favor Klein’s approach as it contains less obscure function calls.

Final Examples

References

Comments

Popular posts from this blog

Twisted Klein: Non-Blocking Recipes

Non-Blocking Recipes Do you like expressjs , but don’t want to switch to Node.js? Want non-blocking execution in Python? Then look no further! Asynchronous execution is the very essence of what makes Klein a contender in todays web framework landscape. It’s also the most difficult concept to grasp since most Pythonistas are not accustomed to asynchronous programming. Hopefully with the addition asyncio to Python’s standard library, this will change. Klein is built atop Twisted and developers can expose Deferred objects for asynchronous behavior. A very brief overview will be given on Twisted Deferred , afterwards aspiring developers are encouraged to read the Twisted documents on the subject (provided in the links near the bottom). Deferred Overview To demonstrate how Deferred objects work, we will create a chain of callback functions that execute after a result is available. Don’t worry if this confuses you right now, the code will clear things up. from __future_

Simple self signed TLS server and client using Twisted

Self signed TLS server and client using Twisted Prerequisites openssl twisted & pyOpenSSL modules- pip install twisted[tls] treq module - pip install treq Basic knowledge of Twisted TCP servers/clients Generate self signed certificate Generate the server's private key using a secret, which is SuperSecretPassword in this case. openssl genrsa -aes256 -passout pass:SuperSecretPassword -out server.key 2048 Perform a CSR (certificate signing request). Ensure the FQDN (fully qualified domain name) matches the hostname of the server, otherwise the server won't be properly validated. openssl req -new -key server.key -passin pass:SuperSecretPassword -out server.csr # Common Name (e.g. server FQDN or YOUR name) []:localhost openssl x509 -req -passin pass:SuperSecretPassword -days 1024 -in server.csr -signkey server.key -out server.crt For development purposes, remove the password from the certificate. openssl rsa -in server.key -out server_no_pass.key -passin pas

Python alias commands that play nice with virtualenv

There are plenty of predefined Python executables, symlinks, and aliases that come bundled with your operating system. These commands come in very handy because it saves you from typing out long commands or chain of scripts. However the downfall of operating system aliases is that they don’t always play nice with virtualenv (or venv if you’re on Python 3). Most predefined aliases use the system’s default Python as the interpreter, which is next to useless when your application runs in a virtual environment. Over the years, I’ve come up with my own Python aliases that play nice with virtual environments. For this post, I tried to stay as generic as possible such that any alias here can be used by every Pythonista. In other words, there will be no aliases for specific frameworks such as running a Django server or starting a Scrappy spider. The following is one of my bash scripts I source: .py-aliases #----- Pip -----# alias pip-list="pip freeze | less" alias pip-search