From 8236edc8205b58b0cf22556ec5f85eb6f469dc3b Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 11:06:49 -0700 Subject: [PATCH 01/15] Update Wave 1 doc --- ada-project-docs/wave_01.md | 47 ++++++++++++++----------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/ada-project-docs/wave_01.md b/ada-project-docs/wave_01.md index a9a1d02f7..b9cb61026 100644 --- a/ada-project-docs/wave_01.md +++ b/ada-project-docs/wave_01.md @@ -55,17 +55,19 @@ We might also consider creating a route helper method that can: ## CRUD for Tasks -### Tips - -- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. - - That said, remember that dictionaries do not have an implied order. This is still true in JSON with objects. When you make Postman requests, the order of the key/value pairings within the response JSON object does not need to match the order specified in this document. (The term "object" in JSON is analogous to "dictionary" in Python.) - - Notice that the details for a Task in the response is shared across all the endpoints that return Task details. Rather than repeating the same literal `dict` structure in each response, we should create a helper method that returns the `dict` structure for a Task, and use it in each relevant endpoint. This will ensure that all our responses are consistent. -- Use the tests in `tests/test_wave_01.py` to guide your implementation. +Use the tests in `tests/test_wave_01.py` to guide your implementation. - You may feel that there are missing tests and missing edge cases considered in this wave. This is intentional. - You have fulfilled wave 1 requirements if all of the wave 1 tests pass. - You are free to add additional features, as long as the wave 1 tests still pass. However, we recommend that you consider the future waves, first. - Some tests use a fixture named `one_task` that is defined in `tests/conftest.py`. This fixture saves a specific task to the test database. +### CRUD Tips + +- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. + - That said, remember that dictionaries do not have an implied order. This is still true in JSON with objects. When you make Postman requests, the order of the key/value pairings within the response JSON object does not need to match the order specified in this document. (The term "object" in JSON is analogous to "dictionary" in Python.) +- Notice that the details for a Task in the response is shared across all the endpoints that return Task details. Rather than repeating the same literal `dict` structure in each response, we should create a helper method that returns the `dict` structure for a Task, and use it in each relevant endpoint. This will ensure that all our responses are consistent. +- Retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. + ### CLI In addition to testing your code with pytest and postman, you can play test your code with the CLI (Command Line Interface) by running `python3 cli/main.py`. @@ -94,12 +96,10 @@ and get this response: ```json { - "task": { - "id": 1, - "title": "A Brand New Task", - "description": "Test Description", - "is_complete": false - } + "id": 1, + "title": "A Brand New Task", + "description": "Test Description", + "is_complete": false } ``` @@ -107,8 +107,6 @@ so that I know I successfully created a Task that is saved in the database. Remember that the knowledge of how to initialize a new model instance from the request dictionary is often left to the model itself, as it allows the model to control which fields are required and how they are initialized. We could add a class method to the Task model that initializes a new instance from a dictionary, and use this method in the route. If all of our models have this method, we could create a route helper method that initializes a new model instance from a dictionary, and use it in this route and any other route that creates a new model instance. -Further, notice that the data nested under the `"task"` key is a dictionary representation of the task that was created. Creating a model helper method to return this dictionary, which we can then use to help build this route response, will improve the consistency of our endpoints. - #### Get Tasks: Getting Saved Tasks As a client, I want to be able to make a `GET` request to `/tasks` when there is at least one saved task and get this response: @@ -132,8 +130,6 @@ As a client, I want to be able to make a `GET` request to `/tasks` when there is ] ``` -Notice that each data item in the list is a dictionary representation of a task. Creating a model helper method to return this dictionary, which we can then use to help build this route response, will improve the consistency of our endpoints. - #### Get Tasks: No Saved Tasks As a client, I want to be able to make a `GET` request to `/tasks` when there are zero saved tasks and get this response: @@ -152,18 +148,15 @@ As a client, I want to be able to make a `GET` request to `/tasks/1` when there ```json { - "task": { - "id": 1, - "title": "Example Task Title 1", - "description": "Example Task Description 1", - "is_complete": false - } + "id": 1, + "title": "Example Task Title 1", + "description": "Example Task Description 1", + "is_complete": false } ``` -Notice that the data nested under the `"task"` key is a dictionary representation of the task that was retrieved. Creating a model helper method to return this dictionary, which we can then use to help build this route response, will improve the consistency of our endpoints. - -Further, we should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. This method could start out only working for Task models. But knowing that we'll be working with Goal models later on, it might be worth generalizing this method to work with any model. +We should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. +- This method could start out only working for Task models. But, knowing that we'll be working with Goal models later on, it might be worth generalizing this method to work with any model. #### Update Task @@ -184,8 +177,6 @@ The response should have a mimetype of "application/json" to keep our API respon Note that the update endpoint does update the `completed_at` attribute. This will be updated with custom endpoints implemented in Wave 3. -We should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. This method could start out only working for Task models. But knowing that we'll be working with Goal models later on, it might be worth generalizing this method to work with any model. - #### Delete Task: Deleting a Task As a client, I want to be able to make a `DELETE` request to `/tasks/1` when there is at least one saved task and get this response: @@ -194,8 +185,6 @@ As a client, I want to be able to make a `DELETE` request to `/tasks/1` when the The response should have a mimetype of "application/json" to keep our API response type consistent. -We should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. This method could start out only working for Task models. But knowing that we'll be working with Goal models later on, it might be worth generalizing this method to work with any model. - #### No Matching Task: Get, Update, and Delete As a client, if I make any of the following requests: From 034378d4eb582878f3ce7b02b3b99007f471e771 Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 11:09:51 -0700 Subject: [PATCH 02/15] Update Wave 1 tests --- tests/test_wave_01.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/tests/test_wave_01.py b/tests/test_wave_01.py index 117245696..fac95a0a3 100644 --- a/tests/test_wave_01.py +++ b/tests/test_wave_01.py @@ -132,14 +132,11 @@ def test_get_task(client, one_task): # Assert assert response.status_code == 200 - assert "task" in response_body assert response_body == { - "task": { - "id": 1, - "title": "Go on my daily walk 🏞", - "description": "Notice something new every day", - "is_complete": False - } + "id": 1, + "title": "Go on my daily walk 🏞", + "description": "Notice something new every day", + "is_complete": False } @@ -169,14 +166,11 @@ def test_create_task(client): # Assert assert response.status_code == 201 - assert "task" in response_body assert response_body == { - "task": { - "id": 1, - "title": "A Brand New Task", - "description": "Test Description", - "is_complete": False - } + "id": 1, + "title": "A Brand New Task", + "description": "Test Description", + "is_complete": False } query = db.select(Task).where(Task.id == 1) From 05b3aa45dd94e7882edc2c0da1d99956d32ab4bd Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 11:25:30 -0700 Subject: [PATCH 03/15] Update Wave 2 & 3 docs --- ada-project-docs/wave_02.md | 9 +++--- ada-project-docs/wave_03.md | 62 +++++++++++++++---------------------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/ada-project-docs/wave_02.md b/ada-project-docs/wave_02.md index 1f3560e3c..1f7b517e1 100644 --- a/ada-project-docs/wave_02.md +++ b/ada-project-docs/wave_02.md @@ -8,15 +8,16 @@ Our task list API allows users to create tasks and get a list of all tasks. Our The following are required routes for wave 2. Feel free to implement the routes in any order within this wave. -### Tips - -- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. -- Use the tests in `tests/test_wave_02.py` to guide your implementation. +Use the tests in `tests/test_wave_02.py` to guide your implementation. - You may feel that there are missing tests and missing edge cases considered in this wave. This is intentional. - You have fulfilled wave 2 requirements if all of the wave 2 tests pass. - You are free to add additional features, as long as the wave 2 tests still pass. However, we recommend that you consider the future waves, first. - Some tests use a fixture named `three_tasks` that is defined in `tests/conftest.py`. This fixture saves three different tasks with three different titles to the test database. +### Tips + +- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. + ### Sorting Tasks: By Title, Ascending As a client, I want to be able to make a `GET` request to `/tasks?sort=asc` when there is more than one saved task, and get an array of tasks sorted by **title**. The titles should be in _ascending_ order, where a task with the title "A" is sorted before a task with the title "B." diff --git a/ada-project-docs/wave_03.md b/ada-project-docs/wave_03.md index 6d15f5d85..ee7f5e537 100644 --- a/ada-project-docs/wave_03.md +++ b/ada-project-docs/wave_03.md @@ -4,24 +4,28 @@ Our task list API allows users to meaningfully use the task resource. Users want to be able to mark a task as "complete" or "incomplete." -We want to design our API so that it stores a task's `completed_at` date as a datetime value in our database. In this scenario, our API does _not_ give users the `completed_at` date... it only gives the information if `is_complete` is `true` or `false`. +We want to design our API so that it stores a task's `completed_at` date as a datetime value in our database. In this scenario, our API does _not_ give users the `completed_at` date – it only gives the information if `is_complete` is `true` or `false`. -A task's `is_complete` is `true` when there is a datetime for the task's `completed_at` value. A task's `is_complete` is `false` when there is a `null`/`None` value for the tasks's `completed_at` value. +A task's `is_complete` is: +- `true` when there is a datetime for the task's `completed_at` value. +- `false` when there is a `null`/`None` value for the tasks's `completed_at` value. ## Requirements The following are required routes for wave 3. Feel free to implement the routes in any order within this wave. -### Tips - -- Use the tests in `tests/test_wave_3.py` to guide your implementation. +Use the tests in `tests/test_wave_3.py` to guide your implementation. - You may feel that there are missing tests and missing edge cases considered in this wave. This is intentional. - You have fulfilled wave 3 requirements if all of the wave 3 tests pass. - You are free to add additional features, as long as the wave 3 tests still pass. However, we recommend that you consider the future waves, first. - A test uses a fixture named `completed_task` that is defined in `tests/conftest.py`. This fixture saves a task with a datetime value in `completed_at` to the test database. + +### Tips + - JSON's value of `true` is similar to Python's value of `True`, and `false` is similar to Python's `False`. - SQL's value of `null` is similar to Python's value of `None`. - Python has a [datetime library](https://docs.python.org/3/library/datetime.html#module-datetime) which we recommend using to represent dates in model attributes. +- Notice that these routes require that we look up a model by its ID, and then update that model. We should be able to reuse the same route helper methods that we have been using in other Task routes to help build these routes. ### Mark Complete on an Incomplete Task @@ -44,12 +48,10 @@ After I have made the `PATCH` request, I can submit a `GET` request to `/tasks/1 ```json { - "task": { - "id": 1, - "title": "Go on my daily walk 🏞", - "description": "Notice something new every day", - "is_complete": true - } + "id": 1, + "title": "Go on my daily walk 🏞", + "description": "Notice something new every day", + "is_complete": true } ``` @@ -74,12 +76,10 @@ After I have made the `PATCH` request, I can submit a `GET` request to `/tasks/1 ```json { - "task": { - "id": 1, - "title": "Go on my daily walk 🏞", - "description": "Notice something new every day", - "is_complete": false - } + "id": 1, + "title": "Go on my daily walk 🏞", + "description": "Notice something new every day", + "is_complete": false } ``` @@ -104,19 +104,13 @@ After I have made the `PATCH` request, I can submit a `GET` request to `/tasks/1 ```json { - "task": { - "id": 1, - "title": "Go on my daily walk 🏞", - "description": "Notice something new every day", - "is_complete": true - } + "id": 1, + "title": "Go on my daily walk 🏞", + "description": "Notice something new every day", + "is_complete": true } ``` -Notice the same dictionary structure for the Task data as in our wave 1 routes. We should be able to use any response model helper that we are using in other Task routes to help build this response. - -Also notice that fundamentally, this route requires that we look up a model by its ID, and then update that model. We should be able to reuse the same route helper methods that we have been using in other Task routes to help build this route. - ### Mark Incomplete on an Incomplete Task Given a task that has: @@ -138,19 +132,13 @@ After I have made the `PATCH` request, I can submit a `GET` request to `/tasks/1 ```json { - "task": { - "id": 1, - "title": "Go on my daily walk 🏞", - "description": "Notice something new every day", - "is_complete": false - } + "id": 1, + "title": "Go on my daily walk 🏞", + "description": "Notice something new every day", + "is_complete": false } ``` -Notice the same dictionary structure for the Task data as in our wave 1 routes. We should be able to use any response model helper that we are using in other Task routes to help build this response. - -Also notice that fundamentally, this route requires that we look up a model by its ID, and then update that model. We should be able to reuse the same route helper methods that we have been using in other Task routes to help build this route. - ## Mark Complete and Mark Incomplete for Missing Tasks Given that there are no tasks with the ID `1`, From e7b9b73c7dda7bed857281eb498d5d6ab95572e4 Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 11:30:48 -0700 Subject: [PATCH 04/15] Update CLI for removed 'task' wrapper --- cli/task_list.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cli/task_list.py b/cli/task_list.py index a1de21db0..92f5330d4 100644 --- a/cli/task_list.py +++ b/cli/task_list.py @@ -6,7 +6,7 @@ def parse_task_from_response(response): if response.status_code >= 400: return None - return response.json()["task"] + return response.json() def create_task(title, description, completed_at=None): query_params = { @@ -25,14 +25,10 @@ def list_tasks(): def get_task(id): response = requests.get(url+f"/tasks/{id}") - if response.status_code != 200: - return None - return parse_task_from_response(response) def update_task(id,title,description): - query_params = { "title": title, "description": description From 439e8f967355fb79cb9ed69fc8ad9ea70878f81f Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 11:37:17 -0700 Subject: [PATCH 05/15] Update Wave 4 doc --- ada-project-docs/wave_04.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ada-project-docs/wave_04.md b/ada-project-docs/wave_04.md index acfc78989..7a513a8bd 100644 --- a/ada-project-docs/wave_04.md +++ b/ada-project-docs/wave_04.md @@ -173,18 +173,13 @@ This feature should not affect other features in other waves, nor should it affe ### Requirement: Intentional Slackbot Token Location -Our Slackbot token is an API key that needs to be protected. - -Include your Slackbot token in your code in an intentional way, following best practices about API keys in code bases. +Our Slackbot token is an API key that needs to be protected. Include your Slackbot token in your code in an intentional way, following best practices about API keys in code bases. ### Requirement: Use Python package `requests` to make HTTP calls -Remember to import this package - -Consider using the keyword argument `data`, `json`, and/or `headers` +Remember to import the `requests` package. Consider using the keyword argument `data`, `json`, and/or `headers`. #### Tips -- Remember to put your Slackbot token in your code in an intentional way, following best practices about API keys in code bases. - In order to get the value of an environment variable, use `os.environ.get()`, just as we used it for the database configuration. - Use your work from the Slack API documentation, the Slack tester, and Postman to guide your implementation. From 4ab686cfdc3ffc2540bfa264eea79083bc9fa789 Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 11:53:21 -0700 Subject: [PATCH 06/15] Update Wave 5 doc --- ada-project-docs/wave_05.md | 52 ++++++++++++++----------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/ada-project-docs/wave_05.md b/ada-project-docs/wave_05.md index f5e3614e0..eeb9c9235 100644 --- a/ada-project-docs/wave_05.md +++ b/ada-project-docs/wave_05.md @@ -3,22 +3,21 @@ ## Goal Our task list API should be able to work with an entity called `Goal`. +- `Goal`s are entities that describe a task a user wants to complete. +- They contain a title to name the goal. -Goals are entities that describe a task a user wants to complete. - -They contain a title to name the goal. - -Our goal for this wave is to be able to create, read, update, and delete different goals. We will create RESTful routes for these different operations. +For this wave, we want to be able to create, read, update, and delete different `Goal`s. We will create RESTful routes for these different operations. ## Writing Tests -This wave requires more test writing. +This wave requires more test writing. The tests you need to write are scaffolded in the `test_wave_05.py` file. - As with incomplete tests in other waves, you should comment out the `Exception` when implementing a test. -- The tests you need to write are scaffolded in the `test_wave_05.py` file. - - These tests are currently skipped with `@pytest.mark.skip(reason="test to be completed by student")` and the function body has `pass` in it. Once you implement these tests you should remove the `skip` decorator and the `pass`. -- For the tests you write, use the requirements in this document to guide your test writing. - - Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. +- These tests are currently skipped with `@pytest.mark.skip(reason="test to be completed by student")` and the function body has `pass` in it. + - Once you implement these tests you should remove the `skip` decorator and the `pass`. + +For the tests you write, use the requirements in this document to guide your test writing. - You can model your tests off of the Wave 1 tests for Tasks. +- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. - Some tests use a [fixture](https://docs.pytest.org/en/6.2.x/fixture.html) named `one_goal` that is defined in `tests/conftest.py`. This fixture saves a specific goal to the test database. @@ -38,6 +37,12 @@ Goals should contain these attributes. **The tests require the title column to b - Don't forget to run: - `flask db migrate` every time there's a change in models, in order to generate migrations - `flask db upgrade` to run all generated migrations +- Similar to the Task model, we could add a class method to the Goal model that initializes a new instance from a dictionary, and use this method in relevant routes. + - If all of our models have this method, we could create a route helper method that initializes a new model instance from a dictionary, and use it in any route that creates a new model instance. +- Also like the Task model, notice that routes that return a JSON response are sending a dictionary representation of the goal that was fetched or created. + - Creating a model helper method to return this dictionary, which we can then use to help build these route responses, will improve the consistency of our endpoints. +- Further, we should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it for relevant routes. + - This method would be very similar in functionality to retrieving a Task model by its ID, so rather than making an entirely new route helper method, we could generalize any similar function to also work with a Goal (or any other model). ## CRUD for Goals @@ -59,19 +64,13 @@ and get this response: ```json { - "goal": { - "id": 1, - "title": "My New Goal" - } + "id": 1, + "title": "My New Goal" } ``` so that I know I successfully created a goal that is saved in the database. -Similar to the Task model, we could add a class method to the Goal model that initializes a new instance from a dictionary, and use this method in the route. If all of our models have this method, we could create a route helper method that initializes a new model instance from a dictionary, and use it in this route and any other route that creates a new model instance. - -Also like the Task model, notice that the data nested under the `"goal"` key is a dictionary representation of the goal that was created. Creating a model helper method to return this dictionary, which we can then use to help build this route response, will improve the consistency of our endpoints. - ### Get Goals: Getting Saved Goals As a client, I want to be able to make a `GET` request to `/goals` when there is at least one saved goal and get this response: @@ -91,8 +90,6 @@ As a client, I want to be able to make a `GET` request to `/goals` when there is ] ``` -Notice that each data item in the list is a dictionary representation of a goal. Creating a model helper method to return this dictionary, which we can then use to help build this route response, will improve the consistency of our endpoints. - ### Get Goals: No Saved Goals As a client, I want to be able to make a `GET` request to `/goals` when there are zero saved goals and get this response: @@ -111,18 +108,11 @@ As a client, I want to be able to make a `GET` request to `/goals/1` when there ```json { - "goal": { - "id": 1, - "title": "Build a habit of going outside daily" - } + "id": 1, + "title": "Build a habit of going outside daily" } ``` -Notice that the data nested under the `"goal"` key is a dictionary representation of the goal that was retrieved. Creating a model helper method to return this dictionary, which we can then use to help build this route response, will improve the consistency of our endpoints. - -Further, we should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. This method would be very similar in functionality to retrieving a Task model by its ID, so rather than making an entirely new route helper method, we could generalize any similar Task model method to work also work with a Goal (or any other model). - - ### Update Goal As a client, I want to be able to make a `PUT` request to `/goals/1` when there is at least one saved goal with this request body: @@ -139,8 +129,6 @@ and get this response: The response should have a mimetype of "application/json" to keep our API response type consistent. -We should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. This method could be written to work for Goal models, Task models, or any other model. - ### Delete Goal: Deleting a Goal As a client, I want to be able to make a `DELETE` request to `/goals/1` when there is at least one saved goal and get this response: @@ -149,8 +137,6 @@ As a client, I want to be able to make a `DELETE` request to `/goals/1` when the The response should have a mimetype of "application/json" to keep our API response type consistent. -We should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. This method could be written to work for Goal models, Task models, or any other model. - ### No matching Goal: Get, Update, and Delete As a client, if I make any of the following requests: From 48fe5936a392b8b0cc2689baa33513ff4c8a1834 Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 11:54:48 -0700 Subject: [PATCH 07/15] Update Wave 5 tests --- tests/test_wave_05.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tests/test_wave_05.py b/tests/test_wave_05.py index 4818cfbfd..1f32b3dab 100644 --- a/tests/test_wave_05.py +++ b/tests/test_wave_05.py @@ -99,12 +99,9 @@ def test_get_goal(client, one_goal): # Assert assert response.status_code == 200 - assert "goal" in response_body assert response_body == { - "goal": { - "id": 1, - "title": "Build a habit of going outside daily" - } + "id": 1, + "title": "Build a habit of going outside daily" } @@ -135,10 +132,8 @@ def test_create_goal(client): assert response.status_code == 201 assert "goal" in response_body assert response_body == { - "goal": { - "id": 1, - "title": "My New Goal" - } + "id": 1, + "title": "My New Goal" } From fffd86f0e46e88692b6b3ee22cef7ecf890846ea Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 12:04:35 -0700 Subject: [PATCH 08/15] Update Wave 6 doc --- ada-project-docs/wave_06.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ada-project-docs/wave_06.md b/ada-project-docs/wave_06.md index c05834ef1..44fbb0773 100644 --- a/ada-project-docs/wave_06.md +++ b/ada-project-docs/wave_06.md @@ -2,7 +2,7 @@ ## Goal -Our users want to associate tasks and goals. Specifically, our users want to designate that there are many tasks that serve one goal. +Our users want to associate `Task`s and `Goal`s. Specifically, our users want to designate that there are many tasks that serve one goal. This wave focuses on creating a one-to-many relationship between goals and tasks, where a goal has-many tasks, and a task belongs to one goal. @@ -10,17 +10,19 @@ When we have many tasks and many goals, users will want to conveniently gather a ## Requirements -First, we should update our models so that the relationship is saved in our database. +First, we should update our models so that the relationship between them is created in our database. Secondly, we should create our new route, `/goals//tasks`, so that our API gives back the right information. +Use the tests in `tests/test_wave_06.py` to guide your implementation. +- Some tests use a fixture named `one_task_belongs_to_one_goal` that is defined in `tests/conftest.py`. + - This fixture uses other fixtures to save a task and a goal to the test database, then associates the task with the goal, and stores that updated relationship in the test database. + ### Tips - Use lesson materials and independent research to review how to set up a one-to-many relationship in Flask. -- Remember to run `flask db migrate` and `flask db upgrade` whenever there is a change to the model. +- Remember to run `flask db migrate` and `flask db upgrade` whenever there is a change to a model. - Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. -- Use the tests in `tests/test_wave_06.py` to guide your implementation. -- Some tests use a fixture named `one_task_belongs_to_one_goal` that is defined in `tests/conftest.py`. This fixture saves a task and a goal to the test database, and uses SQLAlchemy to associate the goal and task together. ### Updates to the Goal Model @@ -37,8 +39,6 @@ After reviewing the strategy for creating a one-to-many relationship, in the Tas - Setting the foreign key to `goal`'s primary key column - Using `Optional` syntax to make the attribute nullable -Remember to run `flask db migrate` and `flask db upgrade` whenever there is a change to the model. - ### Sending a List of Task IDs to a Goal Given: @@ -54,7 +54,7 @@ When I send a `POST` request to `/goals/1/tasks` with this request body: } ``` -Then the three `Task`s belong to the `Goal` and it gets updated in the database, and we get back a `200 OK` with the following response body: +Then the three `Task`s belong to the `Goal` and it gets updated in the database. We get back a `200 OK` with the following response body: ```json { @@ -102,7 +102,7 @@ then I get this response: } ``` -Notice that if we have been using a model helper method to return a dictionary representation of a Task, we can use this method to help build this route response. However, we must notice that there is an additional key in the data for the Task models that are associated with the Goal. This doesn't necessarily mean that we should abandon the model helper method, but we may need to introduce logic to allow it to work in this context. +Notice that if we have been using a model helper method to return a dictionary representation of a Task, we can use this method to help build this route response. This is also true of the Goal model helper method. We may need to introduce logic to allow it to work in this context, or use the existing method to generate the basic dictionary representation of the Goal and then add the additional data for the associated Task models. From 8f37d62dec3b2632687999c08c5a48f697c02dd5 Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 12:08:31 -0700 Subject: [PATCH 09/15] Update Wave 6 doc --- tests/test_wave_06.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/test_wave_06.py b/tests/test_wave_06.py index b22781e19..57462f9d2 100644 --- a/tests/test_wave_06.py +++ b/tests/test_wave_06.py @@ -111,11 +111,9 @@ def test_get_task_includes_goal_id(client, one_task_belongs_to_one_goal): assert "task" in response_body assert "goal_id" in response_body["task"] assert response_body == { - "task": { - "id": 1, - "goal_id": 1, - "title": "Go on my daily walk 🏞", - "description": "Notice something new every day", - "is_complete": False - } + "id": 1, + "goal_id": 1, + "title": "Go on my daily walk 🏞", + "description": "Notice something new every day", + "is_complete": False } From 06474bfe5b08e7bc2f9f540b01569fb5e8e0a942 Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 12:31:45 -0700 Subject: [PATCH 10/15] Remove asserts from tests wave 5 & 6 around removed response wrappers --- tests/test_wave_05.py | 1 - tests/test_wave_06.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_wave_05.py b/tests/test_wave_05.py index 1f32b3dab..b7cc330ae 100644 --- a/tests/test_wave_05.py +++ b/tests/test_wave_05.py @@ -130,7 +130,6 @@ def test_create_goal(client): # Assert assert response.status_code == 201 - assert "goal" in response_body assert response_body == { "id": 1, "title": "My New Goal" diff --git a/tests/test_wave_06.py b/tests/test_wave_06.py index 57462f9d2..727fce93a 100644 --- a/tests/test_wave_06.py +++ b/tests/test_wave_06.py @@ -108,8 +108,7 @@ def test_get_task_includes_goal_id(client, one_task_belongs_to_one_goal): response_body = response.get_json() assert response.status_code == 200 - assert "task" in response_body - assert "goal_id" in response_body["task"] + assert "goal_id" in response_body assert response_body == { "id": 1, "goal_id": 1, From f2138b27664f5e546d6be7036ec5dd9e34c1e91c Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 12:48:10 -0700 Subject: [PATCH 11/15] Small language changes in Wave 1 & 5 docs for consistency & clarity --- ada-project-docs/wave_01.md | 3 ++- ada-project-docs/wave_05.md | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ada-project-docs/wave_01.md b/ada-project-docs/wave_01.md index b9cb61026..b2f141e99 100644 --- a/ada-project-docs/wave_01.md +++ b/ada-project-docs/wave_01.md @@ -56,6 +56,7 @@ We might also consider creating a route helper method that can: ## CRUD for Tasks Use the tests in `tests/test_wave_01.py` to guide your implementation. + - You may feel that there are missing tests and missing edge cases considered in this wave. This is intentional. - You have fulfilled wave 1 requirements if all of the wave 1 tests pass. - You are free to add additional features, as long as the wave 1 tests still pass. However, we recommend that you consider the future waves, first. @@ -66,7 +67,7 @@ Use the tests in `tests/test_wave_01.py` to guide your implementation. - Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. - That said, remember that dictionaries do not have an implied order. This is still true in JSON with objects. When you make Postman requests, the order of the key/value pairings within the response JSON object does not need to match the order specified in this document. (The term "object" in JSON is analogous to "dictionary" in Python.) - Notice that the details for a Task in the response is shared across all the endpoints that return Task details. Rather than repeating the same literal `dict` structure in each response, we should create a helper method that returns the `dict` structure for a Task, and use it in each relevant endpoint. This will ensure that all our responses are consistent. -- Retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. +- Retrieving a model by its ID is a common operation. We should create a route helper method that can retrieve a model by its ID, and use it in relevant routes. ### CLI diff --git a/ada-project-docs/wave_05.md b/ada-project-docs/wave_05.md index eeb9c9235..0bbe680b6 100644 --- a/ada-project-docs/wave_05.md +++ b/ada-project-docs/wave_05.md @@ -37,11 +37,11 @@ Goals should contain these attributes. **The tests require the title column to b - Don't forget to run: - `flask db migrate` every time there's a change in models, in order to generate migrations - `flask db upgrade` to run all generated migrations -- Similar to the Task model, we could add a class method to the Goal model that initializes a new instance from a dictionary, and use this method in relevant routes. +- Similar to the Task model, we should add a class method to the Goal model that initializes a new instance from a dictionary, and use this method in relevant routes. - If all of our models have this method, we could create a route helper method that initializes a new model instance from a dictionary, and use it in any route that creates a new model instance. - Also like the Task model, notice that routes that return a JSON response are sending a dictionary representation of the goal that was fetched or created. - Creating a model helper method to return this dictionary, which we can then use to help build these route responses, will improve the consistency of our endpoints. -- Further, we should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it for relevant routes. +- Further, we should remember that retrieving a model by its ID is a common operation. If it has not been done yet, we should create a route helper method that can retrieve a model by its ID, and use it for relevant routes. - This method would be very similar in functionality to retrieving a Task model by its ID, so rather than making an entirely new route helper method, we could generalize any similar function to also work with a Goal (or any other model). ## CRUD for Goals From 4c0800420b5fdc6a70824334d4e724cf5970cb59 Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 12:58:55 -0700 Subject: [PATCH 12/15] Slight Wave 6 doc update for clarity --- ada-project-docs/wave_06.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ada-project-docs/wave_06.md b/ada-project-docs/wave_06.md index 44fbb0773..f85230e00 100644 --- a/ada-project-docs/wave_06.md +++ b/ada-project-docs/wave_06.md @@ -10,9 +10,9 @@ When we have many tasks and many goals, users will want to conveniently gather a ## Requirements -First, we should update our models so that the relationship between them is created in our database. - -Secondly, we should create our new route, `/goals//tasks`, so that our API gives back the right information. +We should: +1. Update our models so that the relationship between them is created in our database. Secondly, we should +2. Create our new route, `/goals//tasks`, so that our API gives back the right information. Use the tests in `tests/test_wave_06.py` to guide your implementation. - Some tests use a fixture named `one_task_belongs_to_one_goal` that is defined in `tests/conftest.py`. From f109984dbbc6c11f6d2972b203c1222adb3c69c1 Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 12:59:21 -0700 Subject: [PATCH 13/15] Slight Wave 6 doc update for clarity --- ada-project-docs/wave_06.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ada-project-docs/wave_06.md b/ada-project-docs/wave_06.md index f85230e00..3d2b80fa1 100644 --- a/ada-project-docs/wave_06.md +++ b/ada-project-docs/wave_06.md @@ -11,7 +11,7 @@ When we have many tasks and many goals, users will want to conveniently gather a ## Requirements We should: -1. Update our models so that the relationship between them is created in our database. Secondly, we should +1. Update our models so that the relationship between them is created in our database. 2. Create our new route, `/goals//tasks`, so that our API gives back the right information. Use the tests in `tests/test_wave_06.py` to guide your implementation. From 7a466fe6a43b77307760eb661da2dd7c6896b94c Mon Sep 17 00:00:00 2001 From: Kelsey Steven Date: Wed, 20 Aug 2025 13:02:39 -0700 Subject: [PATCH 14/15] Slight Wave 5 doc update for clarity --- ada-project-docs/wave_05.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ada-project-docs/wave_05.md b/ada-project-docs/wave_05.md index 0bbe680b6..78ff49a77 100644 --- a/ada-project-docs/wave_05.md +++ b/ada-project-docs/wave_05.md @@ -6,7 +6,7 @@ Our task list API should be able to work with an entity called `Goal`. - `Goal`s are entities that describe a task a user wants to complete. - They contain a title to name the goal. -For this wave, we want to be able to create, read, update, and delete different `Goal`s. We will create RESTful routes for these different operations. +Our plan for this wave is to be able to create, read, update, and delete different `Goal`s. We will create RESTful routes for these different operations. ## Writing Tests From f116b485df13abbe07d4ac628a918cae78bde285 Mon Sep 17 00:00:00 2001 From: Kelsey Steven <97124999+kelsey-steven-ada@users.noreply.github.com> Date: Wed, 27 Aug 2025 15:51:37 -0700 Subject: [PATCH 15/15] Apply suggestions from code review Co-authored-by: apradoada <110429145+apradoada@users.noreply.github.com> --- ada-project-docs/wave_01.md | 5 ++--- ada-project-docs/wave_03.md | 2 +- ada-project-docs/wave_05.md | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ada-project-docs/wave_01.md b/ada-project-docs/wave_01.md index b2f141e99..434b1fdbf 100644 --- a/ada-project-docs/wave_01.md +++ b/ada-project-docs/wave_01.md @@ -67,7 +67,8 @@ Use the tests in `tests/test_wave_01.py` to guide your implementation. - Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings. - That said, remember that dictionaries do not have an implied order. This is still true in JSON with objects. When you make Postman requests, the order of the key/value pairings within the response JSON object does not need to match the order specified in this document. (The term "object" in JSON is analogous to "dictionary" in Python.) - Notice that the details for a Task in the response is shared across all the endpoints that return Task details. Rather than repeating the same literal `dict` structure in each response, we should create a helper method that returns the `dict` structure for a Task, and use it in each relevant endpoint. This will ensure that all our responses are consistent. -- Retrieving a model by its ID is a common operation. We should create a route helper method that can retrieve a model by its ID, and use it in relevant routes. +- We should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in all applicable routes. + - This method could start out only working for Task models. But, knowing that we'll be working with Goal models later on, it might be worth generalizing this method to work with any model. ### CLI @@ -156,8 +157,6 @@ As a client, I want to be able to make a `GET` request to `/tasks/1` when there } ``` -We should remember that retrieving a model by its ID is a common operation. We should consider creating a route helper method that can retrieve a model by its ID, and use it in this route. -- This method could start out only working for Task models. But, knowing that we'll be working with Goal models later on, it might be worth generalizing this method to work with any model. #### Update Task diff --git a/ada-project-docs/wave_03.md b/ada-project-docs/wave_03.md index ee7f5e537..0527d7b9f 100644 --- a/ada-project-docs/wave_03.md +++ b/ada-project-docs/wave_03.md @@ -4,7 +4,7 @@ Our task list API allows users to meaningfully use the task resource. Users want to be able to mark a task as "complete" or "incomplete." -We want to design our API so that it stores a task's `completed_at` date as a datetime value in our database. In this scenario, our API does _not_ give users the `completed_at` date – it only gives the information if `is_complete` is `true` or `false`. +We want to design our API so that it stores a task's `completed_at` date as a datetime value in our database. In this scenario, our API does _not_ give users the `completed_at` date – it only indicates whether `is_complete` is `true` or `false`. A task's `is_complete` is: - `true` when there is a datetime for the task's `completed_at` value. diff --git a/ada-project-docs/wave_05.md b/ada-project-docs/wave_05.md index 78ff49a77..f8893cea3 100644 --- a/ada-project-docs/wave_05.md +++ b/ada-project-docs/wave_05.md @@ -3,7 +3,7 @@ ## Goal Our task list API should be able to work with an entity called `Goal`. -- `Goal`s are entities that describe a task a user wants to complete. +- `Goal`s are entities that describe a set of tasks a user wants to complete. - They contain a title to name the goal. Our plan for this wave is to be able to create, read, update, and delete different `Goal`s. We will create RESTful routes for these different operations.