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

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...

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...

Embed Scrapy in WSGI Application

WSGI and Scrapy A common question on Scrapy Stackoverflow is "How to use Scrapy with Flask, Django, or any other Python web framework?" Most are used to using the Scrapy’s generated projects and cli options, which make crawling a breeze, but are confused when trying to integrate Scrapy into a WSGI web framework. A common traceback encountered is ReactorNotRestartable , which stems from the underlaying Twisted framework. This occurs because, unlike asyncio or Tornado, Twisted’s eventloop/reactor cannot be restarted once stopped (the reason is a bit out of scope). So it becomes apparent that the trick to integrating Scrapy and WSGI frameworks involves being able to tame Twisted. Luckily, integrating async Twisted code with synchronous code has become quite easy and is only getting easier. In this post, the following will be demonstrated: Embed a crawler in a WSGI app and run it using Twisted’s twist web WSGI server. Embed a crawler in a WSGI app and run it any WSGI serve...