Replies: 9 comments
-
I'm afraid this isn't possible. Starlite's dependency injection mechanism isn't general purpose; It's tied closely to route handlers and requests. So the only solution is to place whatever you need somewhere in the dependency tree. As for your concrete problem, I think this is in fact a bit of a design flaw. I think a solution could be offer an interface on the app to retrieve plugin instances, and for the SQLAlchemyPlugin to provide a more convenient method to create an ad-hoc session. @starlite-api/maintainers I'd like some more input on this. This particular issue "how to get a db session in |
Beta Was this translation helpful? Give feedback.
-
To work around this issue you could define your |
Beta Was this translation helpful? Give feedback.
-
I've always done it this way: from __future__ import annotations
from contextlib import contextmanager
from typing import TYPE_CHECKING, AsyncGenerator
from .session import AsyncSessionFactory
if TYPE_CHECKING:
from sqlalchemy.ext.asyncio import AsyncSession
async def get_db() -> AsyncGenerator[AsyncSession]:
"""Dependency that yields an `AsyncSession` for accessing the database."""
async with AsyncSessionFactory() as db:
yield db
@contextmanager
async def session() -> AsyncSession:
async with AsyncSessionFactory() as db:
return db I use |
Beta Was this translation helpful? Give feedback.
-
I do have a recent experience to add to this. I haven't had to do a lot of work with authn at the starlite layer as we handle it at the network layer for the most part. However, I did need to do something recently that needed it. I reached for a guard first, and then realized that I couldn't inject the session dependency into the guard, so I just used a regular dependency and do the auth in the Dependency provider looked something like this: def provides_service(
provider_id: UUID = Parameter(header="X-PROVIDER-ID"),
api_key: SecretStr = Parameter(header="X-API-KEY"),
db_session: AsyncSession = Dependency(),
) -> Service:
"""Constructs repository and service objects for the request."""
return Service(provider_id=provider_id, api_key=api_key, session=db_session) ...I raise a generic unauthorized at the service layer, and then use exception handlers in starlite to translate that into a http 401 exception. An advantage I see of doing it at the service layer is that the auth logic can be leveraged by cli and workers as well, but if there was a canonical way to access dependencies via guards or middleware at the time, I probably would have ended up just using that in this case. |
Beta Was this translation helpful? Give feedback.
-
I think we can support dependencies in guards. Maybe we can redesign them a bit in general for If we add guards into the dependency graph, it would allow them to receive the same kwargs as dependencies as well, making them more convenient to use since they can opt to receive things such as query params, cookies and headers as needed, without having to go through the Making the same data available in route handlers, dependencies and guards also makes for a better DX imo, since it's a bit more intuitive. |
Beta Was this translation helpful? Give feedback.
-
Agreed! |
Beta Was this translation helpful? Give feedback.
-
Open in issue? |
Beta Was this translation helpful? Give feedback.
-
So to be clear: is the canonical way to implement |
Beta Was this translation helpful? Give feedback.
-
@mje-nz Yes, it's either that or what @peterschutt suggested. |
Beta Was this translation helpful? Give feedback.
-
What's the feature you'd like to ask for.
It would be useful if we could use dependencies from middlewares, guards etc.
I'm not sure it makes sense for them to be magic like they are for route handlers, but if there were a method on
Starlite
that takes a top-level dependency name, collects that dependency's dependencies (if any), and returns a context manager for it that runs cleanups at the end (if any), it would help us keep things DRY.Additional context
I'm trying to implement authentication with JWTAuth. Until now, I had my application structured such that the database interaction is abstracted into repositories, there is a module which sets up the SQLAlchemy plugin and injects a dependency for each repository, and the rest of the application uses only high-level interfaces and types.
However, I can't see how to access these dependencies from
JWTAuth.retrieve_user_handler
, so now I have to un-separate my concerns and repeat some of the database setup in the auth module. Currently I'm usingconnection.app.state.db_engine
and getting a session and a user repository from there.Beta Was this translation helpful? Give feedback.
All reactions