This can be solved in a very readably way by calling the implementation.py functions from storage.py. This way the exception handling only need to be written once. This also allows for computed arguments for the implementations.py functions as well as using their return data, which may or may not be needed. But this is apparently bad practice, thus it is a problem.
Consider the following example, where a User can have multiple Projects, which in turn can have one or multiple Goals. When returning a goal, we have to check that the Project and User ids provided exist and are correct. Sure, you can maybe skip doing this with project id and just use user id, but this problem will anyway, one way or another occur when creating, editing or deleting Goals. The implementation.py file will then look something like below. Note that the handling of the exceptions are rewritten, because when we're getting Project we need to check that the user is correct, and when getting a Goal, we need to check that the Project and User exist or are correct.
def get_project(project_id: int, user_id: int) -> models.Project:
try:
with get_connection() as con:
storage.get_goal(con, project_id, user_id)
except ProjectNotFoundException:
raise ...
except UserNotCorrectException:
raise ...
def get_goal(goal_id: int, project_id: int, user_id: int) -> models.Goal:
try:
with get_connection() as con:
storage.get_goal(con, goal_id, project_id, user_id)
except GoalNotFoundException:
raise ...
except ProjectNotFoundException:
raise ...
except UserNotCorrectException:
raise ...
We might solve this by calling the implementation functions from the router.py file as exemplified below. But this will get messy if we want to use the return data to avoid querying the database multiple times for the same thing. This is however, probably best practice when possible for now.
@router.get(
'/project/{project_id}/goal/get/{goal_id}/',
summary='Returns a goal based on id',
response_model=models.Goal,
)
def get_goal(goal_id: int, project_id: int, user: User = Depends(get_current_active_user)) -> models.Goal:
impl.get_project(project_id, user.id)
return impl.get_goal(goal_id)
Might be possible to solve by modifying get_connection().
This can be solved in a very readably way by calling the implementation.py functions from storage.py. This way the exception handling only need to be written once. This also allows for computed arguments for the implementations.py functions as well as using their return data, which may or may not be needed. But this is apparently bad practice, thus it is a problem.
Consider the following example, where a
Usercan have multipleProjects, which in turn can have one or multipleGoals. When returning a goal, we have to check that theProjectandUserids provided exist and are correct. Sure, you can maybe skip doing this with project id and just use user id, but this problem will anyway, one way or another occur when creating, editing or deletingGoals. Theimplementation.pyfile will then look something like below. Note that the handling of the exceptions are rewritten, because when we're gettingProjectwe need to check that the user is correct, and when getting aGoal, we need to check that theProjectandUserexist or are correct.We might solve this by calling the implementation functions from the
router.pyfile as exemplified below. But this will get messy if we want to use the return data to avoid querying the database multiple times for the same thing. This is however, probably best practice when possible for now.Might be possible to solve by modifying
get_connection().