Skip to content

Commit a3585de

Browse files
authored
Merge pull request #79 from AdaGold/ar/optional-doesnt-mean-optional
Update verbiage in Task List optional enhancements
2 parents 6355329 + c1ec721 commit a3585de

File tree

7 files changed

+77
-32
lines changed

7 files changed

+77
-32
lines changed

ada-project-docs/optional-enhancements.md

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,36 +28,16 @@ How would you write tests for it? How would you implement it?
2828

2929
Your decisions should not break the other tests.
3030

31-
### Model Instance Methods
32-
33-
We can define instance methods in our model classes.
34-
35-
Consider places in your code that deal with one model at a time. Is there any repeated logic or behavior?
36-
37-
Here are some ideas to start:
38-
39-
- Create an instance method in `Task` named `to_dict()`
40-
- Converts a `Task` instance into JSON
41-
- Returns a Python dictionary in the shape of the JSON our API returns in the `GET` `/tasks` route
42-
- Create a class method in `Task` named `from_json()`
43-
- Converts JSON into a new instance of `Task`
44-
- Takes in a dictionary in the shape of the JSON our API receives in the create and update routes
45-
- Returns an instance of `Task`
46-
4731
### Use List Comprehensions
4832

4933
Use list comprehensions in your route functions where applicable.
5034

51-
### Route Helper Methods
52-
53-
If you have not already refactored your route files to use helper methods, do so now!
54-
55-
Consider code with complex or repetitive logic, and refactor it into helper methods. Watch your route files become cleaner and more readable!
56-
5735
### More Query Params
5836

5937
Create the tests and implementation so that the user may
6038

6139
- filter tasks by title
6240
- sort tasks by id
6341
- sort goals by title
42+
43+
Remember that Wave 2 already has a sorting feature for tasks by title, so we might practice creating another route helper method that can be used for sorting across multiple model types. Such a method could even be extended to perform the filtering as well!

ada-project-docs/wave_01.md

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,30 @@ Tasks should contain these attributes. **The tests require the following columns
3636
- We can assume that the value of each task's `completed_at` attribute will be `None`, until wave 3. (Read below for examples)
3737
- We can assume that the API will designate `is_complete` as `false`, until wave 3. (Read below for examples)
3838

39+
## Model Helper Methods
40+
41+
We have seen that we can define instance methods in our model classes. We should practice those skills here by including model helper methods that can:
42+
43+
- Return a Python dictionary in the shape of the JSON our API expects to return for a model instance.
44+
- Create a new model instance from a dictionary, typically retrieved from the JSON sent as a request body.
45+
46+
## Route Helper Methods
47+
48+
Beyond model helper methods, we should also practice creating route helper methods. Especially in this wave, we should consider creating a route helper method that can:
49+
50+
- Retrieve a model instance by its ID.
51+
52+
We might also consider creating a route helper method that can:
53+
54+
- Handle the creation of new instances of a model from a dictionary, returning the expected responses.
55+
3956
## CRUD for Tasks
4057

4158
### Tips
4259

43-
- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any mispellings.
44-
- 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 analagous to "dictionary" in Python.)
60+
- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings.
61+
- 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.)
62+
- 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.
4563
- Use the tests in `tests/test_wave_01.py` to guide your implementation.
4664
- You may feel that there are missing tests and missing edge cases considered in this wave. This is intentional.
4765
- You have fulfilled wave 1 requirements if all of the wave 1 tests pass.
@@ -87,6 +105,10 @@ and get this response:
87105

88106
so that I know I successfully created a Task that is saved in the database.
89107

108+
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.
109+
110+
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.
111+
90112
#### Get Tasks: Getting Saved Tasks
91113

92114
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:
@@ -110,6 +132,8 @@ As a client, I want to be able to make a `GET` request to `/tasks` when there is
110132
]
111133
```
112134

135+
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.
136+
113137
#### Get Tasks: No Saved Tasks
114138

115139
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:
@@ -137,6 +161,10 @@ As a client, I want to be able to make a `GET` request to `/tasks/1` when there
137161
}
138162
```
139163

164+
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.
165+
166+
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.
167+
140168
#### Update Task
141169

142170
As a client, I want to be able to make a `PUT` request to `/tasks/1` when there is at least one saved task with this request body:
@@ -156,6 +184,8 @@ The response should have a mimetype of "application/json" to keep our API respon
156184

157185
Note that the update endpoint does update the `completed_at` attribute. This will be updated with custom endpoints implemented in Wave 3.
158186

187+
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.
188+
159189
#### Delete Task: Deleting a Task
160190

161191
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:
@@ -164,6 +194,8 @@ As a client, I want to be able to make a `DELETE` request to `/tasks/1` when the
164194

165195
The response should have a mimetype of "application/json" to keep our API response type consistent.
166196

197+
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.
198+
167199
#### No Matching Task: Get, Update, and Delete
168200

169201
As a client, if I make any of the following requests:
@@ -179,7 +211,8 @@ The response code should be `404`.
179211
You may choose the response body.
180212

181213
Make sure to complete the tests for non-existing tasks to check that the correct response body is returned.
182-
214+
215+
By using a helper method to retrieve a model by its ID, we could ensure that the response for a non-existing model is consistent across all these routes.
183216

184217
#### Create a Task: Invalid Task With Missing Data
185218

ada-project-docs/wave_02.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The following are required routes for wave 2. Feel free to implement the routes
1010

1111
### Tips
1212

13-
- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any mispellings.
13+
- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings.
1414
- Use the tests in `tests/test_wave_02.py` to guide your implementation.
1515
- You may feel that there are missing tests and missing edge cases considered in this wave. This is intentional.
1616
- You have fulfilled wave 2 requirements if all of the wave 2 tests pass.

ada-project-docs/wave_03.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ The following are required routes for wave 3. Feel free to implement the routes
2323
- SQL's value of `null` is similar to Python's value of `None`.
2424
- 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.
2525

26-
### Mark Complete on an Incompleted Task
26+
### Mark Complete on an Incomplete Task
2727

2828
Given a task that has:
2929

@@ -113,7 +113,11 @@ After I have made the `PATCH` request, I can submit a `GET` request to `/tasks/1
113113
}
114114
```
115115

116-
### Mark Incomplete on an Incompleted Task
116+
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.
117+
118+
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.
119+
120+
### Mark Incomplete on an Incomplete Task
117121

118122
Given a task that has:
119123

@@ -143,6 +147,10 @@ After I have made the `PATCH` request, I can submit a `GET` request to `/tasks/1
143147
}
144148
```
145149

150+
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.
151+
152+
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.
153+
146154
## Mark Complete and Mark Incomplete for Missing Tasks
147155

148156
Given that there are no tasks with the ID `1`,
@@ -154,3 +162,5 @@ Then I get a `404 Not Found`.
154162
You may choose the response body.
155163

156164
Make sure to complete the tests for non-existing tasks to check that the correct response body is returned.
165+
166+
Notice that the behavior for a missing Task is consistent with invalid Task IDs in other Task routes. We should be able to use the same route helper methods that we have been using in other Task routes to help build this route.

ada-project-docs/wave_04.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Press the "Test Method" button!
119119
Scroll down to see the HTTP response. Answer the following questions:
120120

121121
- Did we get a success message? If so, did we see the message in our actual Slack workspace?
122-
- Did we get an error emssage? If so, why?
122+
- Did we get an error message? If so, why?
123123
- What is the shape of this JSON? Is it a JSON object or array? What keys and values are there?
124124

125125
### Verify with Postman

ada-project-docs/wave_05.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ This wave requires more test writing.
1717
- The tests you need to write are scaffolded in the `test_wave_05.py` file.
1818
- 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`.
1919
- For the tests you write, use the requirements in this document to guide your test writing.
20-
- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any mispellings.
20+
- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings.
2121
- You can model your tests off of the Wave 1 tests for Tasks.
2222
- 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.
2323

@@ -68,6 +68,10 @@ and get this response:
6868

6969
so that I know I successfully created a goal that is saved in the database.
7070

71+
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.
72+
73+
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.
74+
7175
### Get Goals: Getting Saved Goals
7276

7377
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:
@@ -87,6 +91,8 @@ As a client, I want to be able to make a `GET` request to `/goals` when there is
8791
]
8892
```
8993

94+
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.
95+
9096
### Get Goals: No Saved Goals
9197

9298
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:
@@ -112,6 +118,10 @@ As a client, I want to be able to make a `GET` request to `/goals/1` when there
112118
}
113119
```
114120

121+
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.
122+
123+
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).
124+
115125

116126
### Update Goal
117127

@@ -129,6 +139,8 @@ and get this response:
129139

130140
The response should have a mimetype of "application/json" to keep our API response type consistent.
131141

142+
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.
143+
132144
### Delete Goal: Deleting a Goal
133145

134146
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:
@@ -137,6 +149,8 @@ As a client, I want to be able to make a `DELETE` request to `/goals/1` when the
137149

138150
The response should have a mimetype of "application/json" to keep our API response type consistent.
139151

152+
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.
153+
140154
### No matching Goal: Get, Update, and Delete
141155

142156
As a client, if I make any of the following requests:
@@ -151,7 +165,9 @@ The response code should be `404`.
151165

152166
You may choose the response body.
153167

154-
Make sure to complete the tests for non-existing tasks to check that the correct response body is returned.
168+
Make sure to complete the tests for non-existing tasks to check that the correct response body is returned.
169+
170+
By using a helper method to retrieve a model by its ID, we could ensure that the response for a non-existing model is consistent across all these routes.
155171

156172
### Create a Goal: Invalid Goal With Missing Title
157173

ada-project-docs/wave_06.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Secondly, we should create our new route, `/goals/<goal_id>/tasks`, so that our
1818

1919
- Use lesson materials and independent research to review how to set up a one-to-many relationship in Flask.
2020
- Remember to run `flask db migrate` and `flask db upgrade` whenever there is a change to the model.
21-
- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any mispellings.
21+
- Pay attention to the exact shape of the expected JSON. Double-check nested data structures and the names of the keys for any misspellings.
2222
- Use the tests in `tests/test_wave_06.py` to guide your implementation.
2323
- 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.
2424

@@ -63,6 +63,8 @@ Then the three `Task`s belong to the `Goal` and it gets updated in the database,
6363
}
6464
```
6565

66+
We will need to validate that the Goal ID, as well as each Task ID exists in the database. A route helper method that can resolve a model instance from its ID would help us validate the IDs in the request body.
67+
6668
### Getting Tasks of One Goal
6769

6870
Given a goal that has:
@@ -100,6 +102,10 @@ then I get this response:
100102
}
101103
```
102104

105+
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.
106+
107+
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.
108+
103109
### Getting Tasks of One Goal: No Matching Tasks
104110

105111
Given a goal that has:

0 commit comments

Comments
 (0)