-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
248 lines (218 loc) · 8.08 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
"""FastAPI CRUD operations with SQLAlchemy."""
import logging
import typing as typ
from enum import Enum
from fastapi import Body, Depends, FastAPI, status
# import all you need from fastapi-pagination
from fastapi_pagination import Page, add_pagination, paginate
from core.common.get_instance import valid_task, valid_undo_task
from core.common.validate_input import (CheckTaskId, GenericTaskInput,
SummaryTask, TaskSuccessMessage,
TaskValidationError, UpdateTask)
from core.methods.delete_method.method import delete_task
from core.methods.get_detail_method.method import get_task
from core.methods.get_list_method.method import (
ConcreteCommonTaskQueryParams, list_tasks,
validate_task_common_query_param)
from core.methods.post_method.method import create_task
from core.methods.undo_method.method import undo_task
from core.methods.update_method.method import update_task
from core.models.models import CurrentTaskContent
# Configure the logger
logging.basicConfig(
level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Create a logger object
logger = logging.getLogger(__name__)
DESCRIPTION = """
**CRUD Taskado** todo Task API with undo feature.
- You need to create an user before creating a task.
- You can create, update, delete, list and undo a task.
- You can `undo` the last `UPDATE`, `DELETE` to the task.
- You can filter the tasks by due_date, task_status, created_by_username, updated_by_username.
"""
tags_metadata = [
{
'name': 'tasks',
'description': 'CRUD operations'},
{
'name': 'undo',
'description': 'Undo the last UPDATE, DELETE to the task',
}
]
app = FastAPI(
title='CRUD Taskado todo Task API',
description=DESCRIPTION,
version='0.0.1',
terms_of_service='https://creativecommons.org/terms/',
contact={
'name': 'Sarit',
'url': 'https://github.com/elcolie',
'email': '[email protected]'
},
license_info={
'name': 'Apache 2.0',
'url': 'https://www.apache.org/licenses/LICENSE-2.0.html'
},
openapi_tags=tags_metadata,
openapi_url='/api/v1/openapi.json',
)
class Tags(Enum):
"""Enum class of tags."""
TASKS = 'tasks'
UNDO = 'undo'
@app.post('/create-task/',
summary='Create todo task',
status_code=status.HTTP_201_CREATED,
response_model=TaskSuccessMessage,
tags=[Tags.TASKS]
)
async def _create_task(
task_input: typ.Annotated[
GenericTaskInput,
Body(
openapi_examples={
'normal': {
'summary': 'Create a task',
'description': 'Create a task with all fields',
'value': {
'description': 'Nice item',
'title': 'Buy a pickled plum juice',
'status': 'pending',
'due_date': '2022-12-31',
'created_by': 1
}
},
'invalid_due_date': {
'name': 'Invalid due date',
'description': 'due_date format is YYYY-MM-DD',
'value': {
'title': 'Buy a pickled plum juice smoothie',
'description': 'Good for health',
'status': 'pending',
'due_date': '2022-99-31',
'created_by': 1
}
},
'invalid_status': {
'name': 'Invalid status',
'description': "Status must be either 'pending', 'in_progress' or 'done'",
'value': {
'title': 'Buy a pickled plum juice',
'description': 'Nice item',
'status': 'done',
'due_date': '2022-12-31',
'created_by': 1
}
}
}
)
]
) -> typ.Any:
"""
Endpoint to create a task.
- **title**: The title of the task.
- **description**: The description of the task.
- **status**: The status of the task. It must be either 'pending', 'in_progress' or 'done'.
- **due_date**: The due date of the task in 'YYYY-MM-DD' format.
- **created_by**: The user id who created the task.
"""
return create_task(task_input)
@app.delete('/{task_id}',
summary='Delete todo task',
status_code=status.HTTP_204_NO_CONTENT, tags=[Tags.TASKS])
async def _delete_task(task_id: CurrentTaskContent = Depends(valid_task)) -> None:
"""
Endpoint to delete a task.
- **task_id**: The id of the task to delete.
"""
delete_task(task_id)
return
@app.get('/{task_id}',
summary='Get task detail',
response_model=UpdateTask, tags=[Tags.TASKS])
async def _get_task(task_id: CurrentTaskContent = Depends(valid_task)) -> typ.Any:
"""
Endpoint to get a task detail.
- **task_id**: The id of the task to get.
"""
return get_task(task_id)
@app.get('/',
summary='List tasks',
response_model=Page[SummaryTask], tags=[Tags.TASKS])
async def _list_tasks(
commons: typ.Annotated[
ConcreteCommonTaskQueryParams,
Depends(validate_task_common_query_param)
],
) -> typ.Any:
"""
Endpoint to list all tasks.
- **due_date**: The due date of the task in 'YYYY-MM-DD' format.
- **task_status**: The status of the task. It must be either 'pending', 'in_progress' or 'done'.
- **created_by_username**: The username of the user who created the task.
- **updated_by_username**: The username of the user who updated the task.
"""
return paginate(list_tasks(commons))
@app.post('/undo/{task_id}',
summary='Undo task',
response_model=TaskSuccessMessage, tags=[Tags.UNDO])
async def _undo_task(task_id: CheckTaskId = Depends(valid_undo_task)) -> typ.Any:
"""
description="Undo last UPDATE, DELETE to the task",
- **task_id**: The id of the task to undo.
"""
return undo_task(task_id)
@app.put('/',
summary='Update task',
description='Make another revision of the task',
response_model=TaskSuccessMessage,
tags=[Tags.TASKS])
async def _update_task(
payload: typ.Annotated[
UpdateTask,
Body(
openapi_examples={
'normal': {
'summary': 'Update a task',
'description': 'Update a task with all fields',
'value': {
'id': 1,
'title': 'Buy a pickled plum juice',
'description': 'Nice item',
'status': 'pending',
'due_date': '2022-12-31',
'created_by': 1
}
},
'invalid_due_date': {
'name': 'Invalid due date',
'description': 'due_date format is YYYY-MM-DD',
'value': {
'id': 1,
'title': 'Buy a pickled plum juice smoothie',
'description': 'Good for health',
'status': 'pending',
'due_date': '2022-99-31',
'created_by': 1
}
},
'invalid_status': {
'name': 'Invalid status',
'description': "Status must be either 'pending', 'in_progress' or 'done'",
'value': {
'id': 1,
'title': 'Buy a pickled plum juice',
'description': 'Nice item',
'status': 'done',
'due_date': '2022-12-31',
'created_by': 1
}
}
}
)
],
) -> TaskSuccessMessage | TaskValidationError:
"""Endpoint to update a task."""
return update_task(payload)
add_pagination(app)