0

I'm working on fastapi web app and currently strugling with one thing.

I'm working on google auth system and my dependency injection does not work as expected.

Here are my endpoints:

@app.route('/login')
async def login(request: Request):
    redirect_uri = request.url_for('auth')
    return await oauth.google.authorize_redirect(request, redirect_uri)

@app.route('/auth')
async def auth(request: Request):
    try:
        access_token = await oauth.google.authorize_access_token(request)
    except OAuthError as e:
        raise CREDENTIALS_EXCEPTION
    _data = access_token["userinfo"]
    if get_or_create_user(data = _data):
        return JSONResponse({'result': True, 'access_token': create_token(_data['email'])})
    raise CREDENTIALS_EXCEPTION

The problem lies in get_or_create_user function.

@validate_payload
def get_or_create_user(data: USER_GOOGLE_DATA, users_repo: UsersRepository = Depends(SQLUsersRepository)) -> model.User:
    _email: str = data.get("email")
    if not _email:
        raise AttributeError("Payload is missing data")
    user: model.User = users_repo.get_by_email(email=_email)
    if not user:
        _user = model.User(**dict(data))
        user = users_repo.add(model.User(_user))
    return user

data is dict with required info to create user and users_repo is crud class. Decorator is just to check if data contains all required keys.

PAYLOAD_KEYS: Tuple[str] = ("email",)

def validate_payload(func: Callable[[USER_GOOGLE_DATA, UsersRepository], model.User]):
    def decorator(*args, **kwargs):
        _data: USER_GOOGLE_DATA = kwargs.get("data")
        for _key in PAYLOAD_KEYS:
            if _key not in _data:
                return None
        return func(_data)
    return decorator

My crud class looks like following:

class SQLUsersRepository(input_boundries.UsersRepository):
    def __init__(self, db: Session or RawDBConnection = Depends(get_db)):
        self._db = db

    def get(self, user_id: UserId) -> model.User:
        user_db = self._db.query(model.User).filter(model.User.id == user_id).first()

        if not user_db:
            raise DBRecordNotFound(f"User with id: '{user_id}' not found.")

        return user_db

    def get_by_email(self, email: str) -> model.User:
        user_db = self._db.query(model.User).filter(model.User.email == email).first()

        if not user_db:
            raise DBRecordNotFound(f"User with email: '{email}' not found.")

        return user_db

    def add(self, user: model.User) -> model.User:
        self._db.add(user)
        self._db.commit()
        self._db.refresh(user)

        return user

    def save(self, user: model.User) -> None:
        user_db = self._db.query(model.User).filter(model.User.id == user.id).first()

        self.add(user=user_db)

    def remove(self, user_id: UserId) -> None:
        user_db = self._db.query(model.User).filter(model.User.id == user_id).first()

        if not user_db:
            raise DBRecordNotFound(f"User with id: '{user_id}' not found.")

        user_db.delete()
        self._db.commit()

The error I receive AttributeError: 'Depends' object has no attribute 'get_by_email'

What's wrong with these dependiences? As far as I remember Depends() works similar to decorator (it triggers first).

xil
  • 1
  • 1
    `Depends` only gets evaluate _in the context of evaluating other dependencies_. If you're calling a regular function (even from a decorated controller function), `Depends` will not get resolved. – MatsLindh Nov 15 '22 at 20:18

0 Answers0