Issue
I am using FastAPI framework and writing some data into PostgreSQL database. The issue I am encountering is that I have a function get_current_user()
that returns user credentials (including email), but I am not sure how to access this data from another function s3_create_upload_files()
.
The reason I want to do this is because I want to write the email address and the filename that I am going to upload to the same line in the database after the file is successfully uploaded.
get_current_user()
async def get_current_user(
request: Request,
db: Session = Depends(get_db),
):
token = request.cookies.get("Authorization")
if token is None:
raise HTTPException(status_code=302, headers={"Location": '/auth/login'})
token = token.split("Bearer ")[-1]
try:
payload = jwt.decode(token, os.getenv('SECRET_KEY'), algorithms=["HS256"])
email: str = payload.get("sub")
if email is None:
raise HTTPException(status_code=302, headers={"Location": '/auth/login'})
except jwt.exceptions.ExpiredSignatureError:
raise HTTPException(status_code=302, headers={"Location": '/auth/login'})
user = db.query(User).filter(User.email == email).first()
if user is None:
raise HTTPException(status_code=302, headers={"Location": '/auth/login'})
print(f'Email is {user.email}')
return user # Ensure 'user' is a User object
s3_create_upload_files()
async def s3_create_upload_files(
file: UploadFile = File(...),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
....CODE HERE,,,,
# Insert data into the database after successful upload
try:
db = SessionLocal()
file_data = User(filename=sanitized_filename, email=current_user.email)
db.add(file_data)
db.commit()
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail=str(e))
finally:
db.close()
I have tried a few different ways to receive the data in s3_create_upload_files()
but all of them cause an error on the HTML side. Same error has come about again "{"detail":"'Depends' object has no attribute 'email'"}"
The error in the backend says
INFO: 192.168.65.1:62133 - "POST /dashboard HTTP/1.1" 500 Internal Server Error
Solution
You could do that using one of the approaches described below.
Option 1 - Return a list
or dict
of data
Return a list
of data from the dependency function, and define a proper parameter in the endpoint to expect these data in the appropriate form.
from fastapi import FastAPI, Depends
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
name: str
age: int
async def get_user_data():
user = User(name='john', age=33)
email = '[email protected]'
return [user, email]
@app.post('/upload')
async def upload(data: list = Depends(get_user_data)):
return {'user': data[0], 'email': data[1]}
To use a dict
instead, apply the following changes to the example above:
# ...
async def get_user_data():
user = User(name='john', age=33)
email = '[email protected]'
return {'user': user, 'email': email}
@app.post('/upload')
async def upload(data: dict = Depends(get_user_data)):
return {'user': data['user'], 'email': data['email']}
Option 1 - Return an object of a custom Python class
Another way to approach this issue would be to create a custom Python class with the relevant data, instantiate the class inside the dependency function to create an object, and finally, return the object to the endppoint. For simplicity, one could use Python's dataclass
—as shown in this answer— where special methods, such as such as __init__()
and __repr__()
can be automatically added.
from fastapi import FastAPI, Depends
from pydantic import BaseModel
from dataclasses import dataclass
app = FastAPI()
class User(BaseModel):
name: str
age: int
@dataclass
class UserData:
user: User
email: str
async def get_user_data():
user = User(name='john', age=33)
email = '[email protected]'
return UserData(user, email)
@app.post('/upload')
async def upload(data: UserData = Depends(get_user_data)):
return {'user': data.user, 'email': data.email}
Option 3 - Use request.state
to store arbitrary data
A further, and maybe simpler, way to store such arbitrary data would be to use request.state
, which would allow you to retrieve these data later in the endpoint, using the Request
object. For more details and examples on this approach (as well as on global dependencies
and request.state
in FastAPI), I would highly suggest having a look at this answer, this answer, as well as this and this.
from fastapi import FastAPI, Depends, Request
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
name: str
age: int
async def get_current_user(request: Request):
user = User(name='john', age=33)
request.state.email = '[email protected]'
return user
@app.post('/upload')
async def upload(request: Request, user: User = Depends(get_current_user)):
return {'user': user, 'email': request.state.email}
Answered By - Chris
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.