forked from stretchyboy/python-todo
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathapi.py
More file actions
123 lines (105 loc) · 3.74 KB
/
api.py
File metadata and controls
123 lines (105 loc) · 3.74 KB
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
from flask_restx import Api, Resource, fields, Namespace
from flask import Blueprint, request, abort
from flask_restx import Api, Resource, Namespace, fields
from flask import Blueprint, request, abort
from todo import Category, Todo, db
from auth import get_current_user
from schemas import TodoSchema, CategorySchema
api_bp = Blueprint('api', __name__, url_prefix='/api')
api = Api(api_bp, title="Todo API", version="1.0",
description="Simple Todo API with categories")
# For docs only
todo_model = api.model('Todo', {
'id': fields.Integer(readOnly=True),
'task': fields.String(required=True),
'user_id': fields.String(readOnly=True),
'category_id': fields.Integer(required=True),
'done': fields.Boolean,
})
todo_input = api.model('TodoInput', {
'task': fields.String(required=True),
'category_id': fields.Integer(required=True),
'done': fields.Boolean(default=False, required=False),
})
category_model = api.model('Category', {
'id': fields.Integer(readOnly=True),
'name': fields.String(required=True),
})
todo_schema = TodoSchema()
category_schema = CategorySchema()
def require_auth():
user = get_current_user()
if not user or not user.get('id'):
abort(401)
return user
@api.route('/categories')
class CategoryList(Resource):
@api.marshal_list_with(category_model)
def get(self):
"""List all categories"""
categories = Category.query.all()
return category_schema.dump(categories, many=True)
@api.route('/todos')
class TodoList(Resource):
@api.marshal_list_with(todo_model)
def get(self):
"""List all todos for the current user"""
user = require_auth()
todos = Todo.query.filter_by(user_id=user['id']).all()
return todo_schema.dump(todos, many=True)
@api.expect(todo_input, validate=True)
@api.marshal_with(todo_model, code=201)
def post(self):
"""Create a new todo for the current user"""
user = require_auth()
data = request.get_json()
errors = todo_schema.validate(data, partial=False)
if errors:
return errors, 400
todo = Todo(
task=data['task'],
category_id=data['category_id'],
user_id=user['id'],
done=data.get('done', False)
)
db.session.add(todo)
db.session.commit()
return todo_schema.dump(todo), 201
@api.route('/todos/<int:todo_id>')
@api.response(404, 'Todo not found')
class TodoResource(Resource):
@api.marshal_with(todo_model)
def get(self, todo_id):
"""Get a todo by ID (must belong to user)"""
user = require_auth()
todo = Todo.query.get_or_404(todo_id)
if todo.user_id != user['id']:
abort(403)
return todo_schema.dump(todo)
@api.expect(todo_input, validate=True)
@api.marshal_with(todo_model)
def put(self, todo_id):
"""Update a todo by ID (must belong to user)"""
user = require_auth()
todo = Todo.query.get_or_404(todo_id)
if todo.user_id != user['id']:
abort(403)
data = request.get_json()
errors = todo_schema.validate(data, partial=True)
if errors:
return errors, 400
todo.task = data.get('task', todo.task)
todo.category_id = data.get('category_id', todo.category_id)
todo.done = data.get('done', todo.done)
db.session.commit()
return todo_schema.dump(todo)
def delete(self, todo_id):
"""Delete a todo by ID (must belong to user)"""
user = require_auth()
todo = Todo.query.get_or_404(todo_id)
if todo.user_id != user['id']:
abort(403)
db.session.delete(todo)
db.session.commit()
return '', 204
data = api.payload