asgiref icon indicating copy to clipboard operation
asgiref copied to clipboard

Specifications about state storage in the scope

Open Kludex opened this issue 2 years ago • 5 comments

On Starlette, we store a lot of information on the scope. Outside the extensions scope key. See our auditing: https://github.com/encode/starlette/discussions/1511.

Also, right now I'm writing a documentation on how to write "pure ASGI middlewares" on Starlette: https://github.com/encode/starlette/pull/1656. And a topic related to this appeared: "how should we store context in the scope"?

Should we just use any custom key? If yes, should we add it to the specifications? If no, is extensions the right key? It doesn't look like, as it seems, that we only use extensions if the ASGI server is participating.

In summary, how should we instruct our users about this topic?

cc @florimondmanca @tomchristie

Kludex avatar Jun 08 '22 05:06 Kludex

😬 So, we probably shouldn't be doing this in Starlette in the first place.

The original design motivation there was that middleware-implemented-as-ASGI was a good idea for frameworks, because it allows for greater cross-framework reusability. So Starlette was designed to use ASGI middleware throughout.

However once you start using that middleware to store additional information (For example an authentication middleware, that stores a user instance in the scope) then you no longer have a cross-framework-reusable middleware, and instead have something that's specific to a particular framework or domain.

So there's a good idea here at the core, that's arguably? been pushed a little too far. (By me.)

Should we just use any custom key?

Keeping our usage there namespaced is at least better than not doing so. But we might(?) want to call out if we/when we have middleware implementations that adding information to the scope in ways not originally intended by the ASGI spec. We could consider namespacing those under say "starlette", so that it's clear that those are bits of framework specific state that's being stored.

tomchristie avatar Jun 08 '22 11:06 tomchristie

Just to be clear: what I'm looking for is orientation on how to document the part of "storing in scope" to an end user, and understand if that should be written in the specs.

I'm not questioning the status quo of those keys in Starlette. 🙏

Kludex avatar Jun 08 '22 13:06 Kludex

I had always envisaged the scope as something that was just opaquely passed down through each layer - the schema says what keys you can expect to find in it, but doesn't say that it should not have any others.

However, in the interests of not name-colliding with future scope items, it may be prudent to place all application scope and data under one specific key? Maybe private, or something like that?

andrewgodwin avatar Jun 14 '22 15:06 andrewgodwin

Or yes, as you suggest @tomchristie, maybe we just say "pick a single key that is very unlikely to be the same name as a HTTP feature" and that's then fine, so starlette is alright.

andrewgodwin avatar Jun 14 '22 15:06 andrewgodwin

I'd suggest using top-level keys: it's much easier to propagate / copy the dict if you can do a shallow copy instead of having to be aware of nested data structures to copy. So I would suggest a structure like {"starlette.router": ...} instead of {"starlette": {"router": ...}}.

The main con to this is that it's harder to make a TypedDict describing the framework specific state.

adriangb avatar Jun 14 '22 15:06 adriangb