Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Middleware is like MITM. It can intercept requests before they are processed by handlers, and responses before they are sent to the client/browser.

Tremolo has two kinds of middleware that can be created. Which are on_request and on_response.

The on_request allows you to put certain code globally at the very front. You can filter, authenticate, then halt (if necessary) before the request goes to / is processed by handlers.

Middleware can be used to extend functionality. For example, tremolo-session is built upon middleware.

Let’s say we have a hello_world handler:

@app.route('/hello')
async def hello_world(**server):
    yield b'Hello'
    yield b'World!'

Normally, the response will be as follows if you do curl -i http://localhost:8000/hello:

HTTP/1.1 200 OK
Date: Thu, 09 Feb 2023 03:22:36 GMT
Server: Tremolo
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Connection: keep-alive

Hello World!

Middleware in action

As Tremolo supports arbitrary request methods, You can halt for example if the received request method is neither GET nor POST:

from tremolo.exceptions import BadRequest

@app.on_request
async def my_request_middleware(**server):
    request = server['request']
    response = server['response']

    if request.method not in (b'GET', b'POST'):
        response.set_status(405, 'Method Not Allowed')
        response.set_content_type('text/plain')

        """Halt with return.

        The request will end at this point.
        The next middlewares (if any), and handlers
        will not be executed.
        """
        return b'Request method %s is not supported!' % request.method

@app.route('/hello')
async def hello_world(**server):
    yield b'Hello'
    yield b'World!'

You might notice, other than using return to halt, you can raise an HTTPException:

from tremolo.exceptions import BadRequest, MethodNotAllowed
# ...

    if request.method not in (b'GET', b'POST'):
        raise MethodNotAllowed('Request method', request.method.decode(), 'is not supported!')
# ...

The response result of curl -X FOO -i http://localhost:8000/hello will be as follows:

HTTP/1.1 405 Method Not Allowed
Content-Type: text/plain
Content-Length: 36
Connection: close
Date: Thu, 09 Feb 2023 03:30:45 GMT
Server: Tremolo

Request method FOO is not supported!

Decorators

In addition to on_request and on_response middleware, there are also decorators such as on_connect and on_close.

They are actually part of the Middleware. But will rarely be used in most applications. They provide you more control, for example when you create a proxy application based on Tremolo.

@app.on_close
async def on_close(**server):
    print('=== CLOSED ===')

Middleware Sequences

These are middleware flows assuming the return value None is used on them.

Request  --> on_connect[1,2,3] --> on_request[1,2,3]
         \                      ^        |
          `.....................'        v
                Keep-Alive            handler
                                         |
                                         v
Response <------------------------ on_response[3,2,1]
    |
    '------> on_close[3,2,1]