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

Is there a Recommended Way of Handling Dependency Injections? #24

Open
Stuwert opened this issue Oct 27, 2021 · 1 comment
Open

Is there a Recommended Way of Handling Dependency Injections? #24

Stuwert opened this issue Oct 27, 2021 · 1 comment

Comments

@Stuwert
Copy link

Stuwert commented Oct 27, 2021

I'm trying to understand the best way to inject the database as a dependency for my graphql queries/mutations.

It looks like context is the appropriate way to do so, and based on reviewing other issues raised on the starlette repo encode/starlette#591, it sounds like the problem was never really solved. Given that starlette is deprecating graphql support and this repo appears to be filling in the gaps of that connection, it felt right to ask the question here.

The workaround described in issue 591 mentions adding the db session to the request via injection on the route, however, that appears to require calling execute on the GraphQL app directly, rather than the app.mount() pattern described in ythe README. I wasn't able to find another way attach the GraphQL app to appropriately, so I'm wondering if I'm missing something or if db dependency injection just isn't possible at the moment.

Is this functionality currently possible to manage or is the expectation that the db will be accessed via things like the SQLAlchemy Graphene connection?

@rachthree
Copy link

rachthree commented Apr 5, 2023

Not sure if this is what you're looking for, but I tried two different ways that retain the app.mount() pattern:

  1. Provide a callable to context_value (this appears to be the intent looking at https://github.com/ciscorn/starlette-graphene3/blob/0.6.0/starlette_graphene3.py#L144 and https://github.com/ciscorn/starlette-graphene3/blob/0.6.0/tests/conftest.py#L98):
from starlette.background import BackgroundTasks
from fastapi import FastAPI

class Context(object):
    def __init__(self, foo_resource):
        self.foo_resource= foo_resource

    async def __call__(self, request):
        return {
            "foo_resource": self.foo_resource,
            "request": request,   # provided to maintain previous default behavior
            "background": BackgroundTasks(),  # provided to maintain previous default behavior
        }

foo_resource = get_foo()
graphql_app = GraphQLApp(schema=schema, context_value=Context(foo_resource))

app = FastAPI()
app.mount("/graphql", graphql_app)
  1. Subclass GraphQLApp and overload _get_context_value:
from fastapi import FastAPI

class AugmentedGraphQLApp(GraphQLApp):
    def __init__(self, *args, **kwargs):
        foo_resource = kwargs.pop("foo_resource")
        super().__init__(*args, **kwargs)

        self.foo_resource = foo_resource 

    async def _get_context_value(self, request):
        context = await super()._get_context_value(request)
        context["foo_resource"] = self.foo_resource
        return context

foo_resource = get_foo()
graphql_app = AugmentedGraphQLApp(schema=schema, foo_resource=foo_resource)

app = FastAPI()
app.mount("/graphql", graphql_app)

I was then able to use context["foo_resource"] using both ways. Disclaimer: I was using graphene-sqlalchemy, so in actuality I had to use info.context["foo_resource"]. I know you were trying to avoid using the SQLAlchemy Graphene connection but I had to use another client (my foo_resource contacting another server) on top of using graphene-sqlalchemy in my project. I would think having the DB session as foo_resource would work.

Edit: missing lines of code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants