Skip to content

Maybellene Aung C22 task list#42

Open
mayboolean wants to merge 13 commits intoAda-C22:mainfrom
mayboolean:main
Open

Maybellene Aung C22 task list#42
mayboolean wants to merge 13 commits intoAda-C22:mainfrom
mayboolean:main

Conversation

@mayboolean
Copy link

No description provided.

Copy link

@yangashley yangashley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on task-list-api!

@@ -1 +1,89 @@
from flask import Blueprint No newline at end of file
from flask import Blueprint, Response, request, abort, make_response

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response, abort, and make_response are imported but never accessed so should be removed.

@@ -1 +1,118 @@
from flask import Blueprint No newline at end of file
from flask import Blueprint, request, Response, abort, make_response

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response, is imported but never accessed so should be removed.


class Goal(db.Model):
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
title: Mapped[str]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider whether the this column for Goal should be nullable. It feels unconventional to allow someone to create a goal that gets saved to the DB without a title.


class Task(db.Model):
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
title: Mapped[str]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with Goal, consider which of the columns for Task should be nullable and which should not be.

Comment on lines +11 to +15
goal_as_dict = {}
goal_as_dict["id"] = self.id
goal_as_dict["title"] = self.title

return goal_as_dict

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can also directly return a dictionary literal

Suggested change
goal_as_dict = {}
goal_as_dict["id"] = self.id
goal_as_dict["title"] = self.title
return goal_as_dict
return {
"id": self.id,
"title": self.title
}

db.session.commit()
response = {
"id": goal.id,
"task_ids": task_ids

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notice that task_ids comes from the request body (line 23). Instead of taking the client-provided value, it would be nice to return a response that has task ids that we get from the goal that we fetched from the db on line 21. This way we know for sure that we're returning data from our source of truth (the DB) instead of just echoing back what the user sent to the API (what we get from request_body["task_ids"])

You'd have to grab tasks from goal like:

tasks_from_goal = goal.tasks
task_ids_from_goal = [task.id for task in tasks_from_goal]

 return {
        "id": int(goal_id),
        "task_ids": task_ids_from_goal
}

goal = validate_model(Goal, goal_id)
request_body = request.get_json()
task_ids = request_body["task_ids"]
tasks = Task.query.filter(Task.id.in_(task_ids)).all()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The <Model>.query syntax has been deprecated since SQLAlchemy 2.0 and should not be used for new development.

Review the docs here

Here, I'd probably use your validate_model method since task_ids are values that are grabbed from the request body that the client sent with the request. Since we can't assume that they're valid, we can validate:

Suggested change
tasks = Task.query.filter(Task.id.in_(task_ids)).all()
tasks = [validate_model(Task, task_id) for task_id in task_ids]

Comment on lines +103 to +117
def validate_model(Task, task_id):
try:
task_id = int(task_id)
except:
response = {"message": f"Task {task_id} is invalid"}
abort(make_response(response, 400))

query = db.select(Task).where(Task.id == task_id)
task = db.session.scalar(query)

if not task:
response = {"message": f"Task {task_id} was not found"}
abort(make_response(response, 404))

return task

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this duplicates the logic in validate_model in route_utilities.py. This should be removed so that you can use the more generic version of this helper function

Comment on lines +67 to +69
path = "https://slack.com/api/chat.postMessage"
token = os.environ.get("SLACK_BOT_TOKEN")
channel_id = "C07V4J7ABF1"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job using variables to reference these values so you don't have string literals embedded below. Since these are constant variables, they should be named with all capital letters.

"text": f"Someone just completed the task {task.title}"
}

requests.post(path, headers=headers, json=data)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer all the logic relating to making a call to the Slack API be encapsulated in a helper function (maybe something like call_slack_api). This would keep this route more concise and reduce the number of responsibilities the logic has to account for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants