Starlette: [Document] Order of middlewares

Created on 10 Apr 2019  路  4Comments  路  Source: encode/starlette

I just started a project with starlette awesome, and found a small issue about the docs related on the order of execution of middlewares... My case, is so usual, like in django:

auth_middleware that depends on session_middleware

Seems like the order is inverse on the order you declare them:

app.add_middleware(AuthenticationMiddleware, backend=middlewares.AuthBackend())
app.add_middleware(middlewares.SessionMiddleware)

The session one is executed first but needs to be added later. I'm not against it, it's an onion, and can be seen in both directions... But I thought that at least should be documented.

On the API side, perhaps is a nice idea, to just instantiate them on a single call, like:

app.add_middlewares([
   middlewareX, middlewareY  # in order of execution... (at least when the request is entering..)
])

Most helpful comment

had the same issue, just adding some documentation would be great as this is a pretty opaque bug to fix.

All 4 comments

Yeah, I'm not a fan of how it is at the moment, but it's a bit unavoidable with the current style. (We can only wrap middleware around what's already been added.)

And yes, we'll eventually do something more like this...

middleware = [
    Middleware(TrustedHostMiddleware, allowed_hosts=ALLOWED_HOSTS),
    Middleware(HTTPSRedirectMiddleware, enabled=not DEBUG),
    Middleware(SessionMiddleware, backend=CookieSignedSessions(secret_key=SECRET_KEY)),
    Middleware(AuthMiddleware, backend=DatabaseAuthBackend(model=User)),
]

app = Starlette(
    debug=DEBUG,
    routes=routes,
    events=events,
    middleware=middleware,
    exception_handlers=exception_handlers
)

See https://github.com/encode/starlette/issues/396

Something like this?

class App(Starlette):
    async def __call__(self, scope, receive, send):
        scope['app'] = self
        # middlewares could be a list
        # and also some kind of predicates could be added 
        # to just at runtime, change the middlware chain.
        # or the result, could just be cached.
        result = compose(
            self.router,
            (TransactionMiddleware, ),
            (ExceptionMiddleware, dict(debug=self.debug)),
            (ServerErrorMiddleware, dict(debug=self.debug))
        )
        await result(scope, receive, send)


def compose(initial, *args):
    base = initial
    for arg in args:
        if len(arg) == 2:
            klass, kwargs = arg
            base = klass(base, **kwargs)
        elif len(arg) == 1:
            klass = arg[0]
            base = klass(base)
    return base


app = App(debug=True)

had the same issue, just adding some documentation would be great as this is a pretty opaque bug to fix.

Thank you so much @jordic !! Should definitely be in the doc imo.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kouohhashi picture kouohhashi  路  3Comments

berislavlopac picture berislavlopac  路  5Comments

hyperknot picture hyperknot  路  6Comments

koddr picture koddr  路  6Comments

Ekuzkamaza picture Ekuzkamaza  路  3Comments