Middleware¶
Middleware provides a means of applying common tasks to a request without having to repeat the code.
For example one wanted to compress the output of request handlers, one might add such middleware that would take the output of a request handler and compress it. Another example would be authentication, The middleware could check if a user had logged in before allowing the request handler to be called.
Global middleware¶
The following example creates a chain of two middleware functions which add
content to a "message" provided by the context
field in the request.
The source code for the following example can be found here (and here here with typing).
import uvicorn
from bareasgi import Application, text_writer
async def first_middleware(request, handler):
print("First middleware - entry")
request.context['message'] = 'This is first the middleware. '
response = await handler(request)
print("First middleware - exit")
return response
async def second_middleware(request, handler):
print("Second middleware - entry")
request.context['message'] += 'This is the second middleware.'
response = await handler(request)
print("Second middleware - exit")
return response
async def http_request_callback(request):
return HttpResponse(
200,
[(b'content-type', b'text/plain')],
text_writer(request.context['message'])
)
app = Application(
middlewares=[
first_middleware,
second_middleware
]
)
app.http_router.add(
{'GET', 'POST', 'PUT', 'DELETE'},
'/',
http_request_callback
)
uvicorn.run(app, port=9009)
The point at which the middleware is applied is on the application.
app = Application(
middlewares=[
first_middleware,
second_middleware
]
)
If we look at the first middleware function we can see it takes one more
argument, the handler
, than a request handler.
async def first_middleware(request, handler):
print("First middleware - entry")
request.context['message'] = 'This is first the middleware. '
response = await handler(request)
print("First middleware - exit")
return response
The handler
is the next function to call. We can see with the two print
statement that the middleware completely wraps the subsequent handler. This
gives us control of both the inputs and the outputs.
Inspecting the output of the program we can see the following results when we browse to the page.
First middleware - entry
Second middleware - entry
Second middleware - exit
First middleware - exit
Route local middleware¶
We can also apply the middleware to a specific route.
For example:
from bareasgi.middleware import make_middleware_chain
...
app = Application(info={'message': 'Unmodified'})
app.http_router.add(
{'GET', 'POST', 'PUT', 'DELETE'},
'/with',
make_middleware_chain(first_middleware, second_middleware, handler=http_request_callback)
)
app.http_router.add(
{'GET', 'POST', 'PUT', 'DELETE'},
'/without',
http_request_callback
)
Now if we brows to http://localhost:9009/with we can see the middleware being called, but when we browse to http://localhost:9009/without it is not.
The source code for this example can be found here (and here here with typing).
What next?¶
Either go back to the table of contents or go to the WebSockets tutorial.