I have a fastAPI project that talks to a Cosmos database.
All of my fastAPI routes are async (async def ...).
I need an async class that will perform CRUD operations of the Cosmos DB.
The problem I'm having is figuring out a constructor for the class.
I want the constructor to:
- Take in the CosmosClient as an arg (azure.cosmos.aio.CosmosClient)
- Use the client to make sure the database is created
- Use the client to make sure the container is created
Something like this:
class CosmosCRUD:
def __init__(self, client: CosmosClient):
self.client = CosmosClient
self.database = await self.client.create_database_if_not_exists("MY_DATABASE_NAME")
self.container = await self.database.create_container_if_not_exists("MY_CONTAINER_NAME", partition_key=...)
Unfortunately, you can only await inside of async functions, and __init__ can't be async, so the code above doesn't work.
As far as I can tell, there's a few solutions:
- Create a new event loop inside of
__init__and run the async code that gets the db and container within that- As far as I can tell, that means that fastAPI will stop processing all requests any time an instance of this class is being created, which is probably going to be on every request. This will absolutely destroy performance of the entire app
- Ignore
__init__and create a new async constructor function likecreatethat users of this class need to call- The IDE (PyCharm) doesn't know that
createis the constructor that will always be called first. Any instance variables created in this new constructor that you try to use in other methods will be flagged as non-existing by the IDE, because they weren't created in__init__ - I tried having both a
createasync classmethod that is the actual constructor, and an__init__method where I just added declarations for any instance variables created increate, with the types (ex:self.client: CosmosClient) but the IDE still complains they don't exist
- The IDE (PyCharm) doesn't know that
- Use dependency injection somehow
- Something like this: https://stackoverflow.com/a/65247387/6423456
- Unfortunately, my
__init__method is taking the client as an argument, and needs to pass it to the function being injected - In the example referenced above, that would be like needing to pass the
aarg to theasync_depbeing injected. - Is that even possible? I'm guessing not
Is there a good way to have async code inside of a constructor, without making the IDE unhappy about missing instance variables?
__init__if you want, there are several ways for doing so, I mentioned one here.