Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: make SessionMiddleware return custom types #3470

Open
guacs opened this issue May 5, 2024 · 3 comments
Open

Enhancement: make SessionMiddleware return custom types #3470

guacs opened this issue May 5, 2024 · 3 comments
Labels
Enhancement This is a new feature or request

Comments

@guacs
Copy link
Member

guacs commented May 5, 2024

Summary

Currently, the BaseSessionBackend handles serialization of custom types (such as Struct, BaseModel etc.) using the type encoders set by the user. However, when it deserializes the data, the user will not get back the types that was initially serialized but only a dictionary. This is a bit inconsistent and removes type safety and other IDE/editor benefits when accessing data from request.session unless they manually convert the returned dictionary into a class or cast it into a TypedDict.

For example,

from msgspec import Struct

class Session(Struct):
    user_id: int
    user_role: Role

async def login(data: Credentials, request: Request, user_service: UserService) -> None:
    user = await user_service.login_user(data)
    
    # Here the `Session` gets serialized properly without issues.
    request.set_session(Session(user.user_id, user.role))
    
async def some_view(request: Request) -> None:
    # Current way since `request.session` returns a `dict[str, Any]` which is
    # due to `BaseSessionBackend.deserialize_data` returning a dictionary.
    session_dict = request.session
    session = Session(**session_dict)
    
    # Proposed way.
    session = request.session
    assert isinstance(session, Session) # True

It would be nice if the session config could be given a type to which the session middleware (or rather, the session backend) would deserialize the session data into.

Basic Example

No response

Drawbacks and Impact

There may be some difficulty in making this backwards compatible if we want to make request.session return a generic type since we would have to add another generic parameter to Request. If this is not possible, users could do something like session = cast(Session, request.session) and the breaking changes could be made in v3. This also may require changes in the API of BaseSessionBackend.deserialize_data to allow it to take a Scope in order to get the type decoders as done in BaseSessionBackend.serialize_data.

Unresolved questions

No response


Note

While we are open for sponsoring on GitHub Sponsors and
OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.

Check out all issues funded or available for funding on our Polar.sh dashboard

  • If you would like to see an issue prioritized, make a pledge towards it!
  • We receive the pledge once the issue is completed & verified
  • This, along with engagement in the community, helps us know which features are a priority to our users.
Fund with Polar
@guacs guacs added the Enhancement This is a new feature or request label May 5, 2024
@peterschutt
Copy link
Contributor

since we would have to add another generic parameter to Request.

I'd like to push back a little bit on this. Request[UserT, AuthT, StateT] is already not great UX, IMO. Maybe, once middleware can participate in DI, the need to access these things via a Request object goes away??

@provinzkraut
Copy link
Member

Maybe, once middleware can participate in DI, the need to access these things via a Request object goes away??

Yes, that's more reasonable. Injecting sessions from e.g. a session-plugin that provides the necessary middlewares/DI providers seems more practical.

@guacs
Copy link
Member Author

guacs commented May 8, 2024

since we would have to add another generic parameter to Request.

I'd like to push back a little bit on this. Request[UserT, AuthT, StateT] is already not great UX, IMO. Maybe, once middleware can participate in DI, the need to access these things via a Request object goes away??

Agreed. I really like the idea of being able to inject the session as part of DI. Then we should just hold back on this until v3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement This is a new feature or request
Projects
Status: Triage
Development

No branches or pull requests

3 participants