I can use MongoDB with FastAPI either
- with a global
client: motor.motor_asyncio.AsyncIOMotorClient
object, or else - by creating one during the
startup
event per this SO answer which refers to this "Real World Example".
However, I also want to use fastapi-users since it works nicely with MongoDB out of the box. The downside is it seems to only work with the first method of handling my DB client connection (ie global). The reason is that in order to configure fastapi-users, I have to have an active MongoDB client connection just so I can make the db
object as shown below, and I need that db
to then make the MongoDBUserDatabase
object required by fastapi-users:
# main.py
app = FastAPI()
# Create global MongoDB connection
DATABASE_URL = "mongodb://user:paspsword@localhost/auth_db"
client = motor.motor_asyncio.AsyncIOMotorClient(DATABASE_URL, uuidRepresentation="standard")
db = client["my_db"]
# Set up fastapi_users
user_db = MongoDBUserDatabase(UserDB, db["users"])
cookie_authentication = CookieAuthentication(secret='lame secret' , lifetime_seconds=3600, name='cookiemonster')
fastapi_users = FastAPIUsers(
user_db,
[cookie_authentication],
User,
UserCreate,
UserUpdate,
UserDB,
)
After that point in the code, I can import the fastapi_users Routers. However, if I want to break up my project into FastAPI Routers of my own, I'm hosed because:
- If I move the
client
creation to another module to be imported into both myapp
and my routers, then I have different clients in different event loops and get errors likeRuntimeError: Task <Task pending name='Task-4' coro=<RequestResponseCycle.run_asgi() running at /usr/local/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py:389> cb=[set.discard()]> got Future <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/local/lib/python3.8/asyncio/futures.py:360]> attached to a different loop
(touched on in this SO question) - If I user the solutions of the "Real World Example", then I get stuck on where to build my
fastapi_users
object in my code example: I can't do it inmain.py
because there's nodb
object yet.
I considered making the MongoDBUserDatabase
object as part of the startup
event code (ie within async def connect_to_mongo()
from the Real World Example), but I'm not able to get that to work either since I can't see how to make it work.
How can I either
- make a global MongoDB client and FastAPI-User object in a way that can be shared among my main
app
and severalrouters
without "attached to a different loop" errors, or - create fancy wrapper classes and functions to set up FastAPI users with the
startup
trigger?