Middleware¶
The middleware pipeline is defined with the asgi_middleware configuration property.
It must contain a list of functions that receive the next app in the pipeline and
must return a plain asgi middleware instance:
def middleware_factory(app):
async def inner(scope, receive, send):
await app(scope, receive, send)
return inner
Qualquer middleware asgi pode ser utilizado no pipeline de middleware. Por exemplo, é possível utilizar o SessionMiddleware do starlette:
from starlette.middleware.sessions import SessionMiddleware
def session_middleware(app, settings, di):
return SessionMiddleware(
app,
secret_key=settings.session.secret_key
)
settings = {
"asgi_middleware": [
"application.middleware.session_middleware"
],
"session": {
"secret_key": "super_secret_key",
},
}
Utilização¶
Para demonstrar o sistema de middleware, nós criaremos um middleware temporizador que exibirá no console o tempo gasto no processamento da requisição:
from asgikit.requests import Request
from asgikit.responses import respond_json
from zayt.web import get
@get
async def hello(request: Request):
await respond_json(
request.response,
{"greeting": "Hello, World!"}
)
from collections.abc import Callable
from datetime import datetime
import structlog
from zayt.di import service
logger = structlog.get_logger()
def timing_middleware(app, settings, di):
async def inner(scope, receive, send):
request_start = datetime.now()
await app(scope, receive, send)
request_end = datetime.now()
delta = request_end - request_start
logger.info("request duration", duration=str(delta))
return inner
settings = {
"asgi_middleware": [
"application.middleware.timing_middleware",
],
}
Dependências do middleware¶
Funções de middleware podem receber serviços como parâmetros. Nós podemos reescrever o middleware temporizador para persistir os tempos usando um serviço ao invés de imprimir no console:
from datetime import datetime
from application.service import TimingService
class TimingMiddleware:
def __init__(self, app, timing_service: TimingService):
self.timing_service = timing_service
async def __call__(self, scope, receive, send):
request_start = datetime.now()
await app(scope, receive, send)
request_end = datetime.now()
await self.timing_service.save(request_start, request_end)
async def timing_middleware(app, timing_service: TimingService):
timing_service = await di.get(TimingService)
return TimingMiddleware(app, timing_service)
from datetime import datetime
from zayt.di import service
@service
class TimingService:
async def save(start: datetime, end: datetime):
...
Arquivos estáticos e uploads¶
The static_files_middleware() and
uploaded_files_middleware() provide a way of
serving static content and user uploaded files.
Há dois middlewares separados para permitir tratamento distinto no pipeline de middleware. Por exemplo, você poderia definir que os uploads serão servidos após autorização, enquanto os arquivos estáticos permanecem publicamente acessíveis.
Utilização¶
Primeiro você precisa ativar os middlewares no settings.py
settings = {
"asgi_middleware": [
"zayt.web.middleware.files.static_files_middleware",
"zayt.web.middleware.files.uploaded_files_middleware",
],
}
Após isto, arquivos localizados nos diretórios resourcres/static e resources/uploads serão serão servidos em /static e /uploads/, respectivamente.
Mapeamento de arquivos estáticos¶
Você pode mapear caminhos para arquivos estáticos específicos para, por exemplo, servir o favicon em /favicon.ico apontando para um arquivo em resources/static/:
settings = {
"asgi_middleware": [
"zayt.web.middleware.files.static_files_middleware",
],
"staticfiles": {
"mappings": {
"favicon.ico": "my-icon.ico"
},
},
}
Opções de configuração¶
As opções disponíveis para configurar o static_files_middleware() e o uploaded_files_middleware() são mostradas abaixo:
settings = {
"staticfiles": {
"path": "/static", # (1)
"root": "resources/static", # (2)
"mappings": {},
},
"uploadedfiles": {
"path": "/uploads", # (3)
"root": "resources/uploads", # (4)
},
}
Nota
Caminho onde os arquivos estáticos serão servidos
Diretório onde os arquivos estáticos são localizados
Caminho onde os uploads são servidos
Diretório onde os uploads são localizados