#Yield async_session as dependency to retrieve_user_handler

1 messages · Page 1 of 1 (latest)

clever rivet
#

Hey Folks,

I am currently trying my luck at putting together the examples from the docs. I used the SQLAlchemy-Plugin to init my DB-Connection like so:

sqlalchemy_config = SQLAlchemyConfig(
    connection_string="sqlite+aiosqlite:///test.sqlite", dependency_key="async_session"
)
sqlalchemy_plugin = SQLAlchemyPlugin(config=sqlalchemy_config)
dto_factory = DTOFactory(plugins=[sqlalchemy_plugin])

I can use the dependecy async_session in my UserController for basic CRUD operations by including
async_session: AsyncSession in the function params and can access the session in the function

When trying to implement the JWT-Backend I implemented the retrieve_user_handler as follows:

async def retrieve_user_handler(token: Token, connection: ASGIConnection, async_session: AsyncSession
                                ) -> User | None:
    user_sub = token.sub
    if user_sub:
        res = await async_session.scalars(select(User).where(User.name == user_sub))
        req_user: User | None = res.one_or_none()
        return req_user
    return None

The async_session is not injected like in the UserController. What is the Starlite way to get the session for the handler? Is there some kind of magic with Provide() that I am missing?

silent ferry
#

Here's what I'm currently doing. It's not the "same" session object from the request, but it hasn't been a problem so far. If there's a better way to do this, I'm interested as well.

async def current_user_from_local_token(token: Token, connection: ASGIConnection[Any, Any, Any]) -> "User":
    async with sqlalchemy_plugin.async_session_factory() as db_session:
        user = await services.users.get_by_email(db_session, token.sub)
        if user and user.is_active:
            return user
    raise NotAuthorizedException("Unable to authenticate token.")
clever rivet
#

Thanks, that seems to work 👍

candid bison
#

I'm trying to do the same thing, and I'd be happier if I could do it without tangling my layers together. I have all the infrastructure layer setup in its own module, and everything else uses injected (application layer) repositories.

Is it possible to resolve a dependency from outside a route handler?

pliant ridge
#

If you're using the sqlalchemy plugin I believe the AsyncSession param needs to be named db_session

#

I do something somewhat similar:

# user_dependencies.py
def get_user_service(db_session: AsyncSession) -> UserService:
    return UserService(session=db_session)
# user_controller.py
dependencies = {"user_service": Provide(get_user_service)}

@post(path="/register")
async def register(
    self, data: RegisterRequest, request: Request, user_service: UserService,
) -> RegisterResponse:
    user = await user_service.get_by_email(email=data.email)
silent ferry
#

I like this pattern as well. I don't think it works in this case because he's referring to the login_handler callable that's passed into the Authentication configuration.

pliant ridge
#

Ahh mb

silent ferry
#

the retrieve_user_handler

pliant ridge
#

Yeah I hadn't seen that, makes sense

candid bison
#

Yeah exactly, that's how I would like it to work, but dependencies aren't magic outside a route handler, and I don't know how to use them without the magic