/
app.py
executable file
·133 lines (97 loc) · 3.68 KB
/
app.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
#!flask/bin/python
"""Flask server that demonstrates serving APIs.
Serves similar same API twice, both by hand and using Flask-restless.
/api : created using Flask-restless
/api/tasks
/api2 : created by making routes and doing work directly
/api2/v1.0/tasks
"""
from flask import Flask, jsonify, request, make_response, abort, url_for
from flask.ext.restless import APIManager
from flask_httpauth import HTTPBasicAuth
from model import connect_to_db, Tasks, db
app = Flask(__name__)
auth = HTTPBasicAuth()
@auth.get_password
def get_password(username):
#TO DO: implement users and api keys on our db
if username == 'marina':
return 'python'
return None
@auth.error_handler
def unauthorized():
# Unfortunately web browsers have the nasty habit of showing an ugly
# login dialog box when a request comes back with a 401 error code.
# We could distract the browser by throwing an error like 403 (Forbidden)
# But it violates the HTTP standard
return make_response(jsonify({'error': 'Unauthorized access'}), 401)
@app.route('/todo/api2/v1.0/tasks', methods=['GET'])
def get_tasks():
tasks = [to_dict(t) for t in Tasks.query.all()]
return jsonify(tasks=tasks)
@app.route('/todo/api2/v1.0/tasks', methods=['POST'])
def add_tasks():
if not request.json or 'title' not in request.json:
abort(400)
else:
new_task = Tasks(task_title=request.json['title'],
task_description=request.json.get('description', ''))
db.session.add(new_task)
db.session.commit()
# Return HTTP status code 201 (the code for created), with body being new ID
return jsonify(new_task.task_id), 201
@app.route('/todo/api2/v1.0/tasks/<int:task_id>', methods=['GET'])
# @auth.login_required
def get_task(task_id):
t = Tasks.query.get_or_404(task_id)
return jsonify(to_dict(t))
@app.route('/todo/api2/v1.0/tasks/<int:task_id>', methods=['PUT', 'PATCH'])
def update_task(task_id):
t = Tasks.query.get_or_404(task_id)
if not request.json:
abort(400)
if 'title' in request.json:
if type(request.json['title']) != unicode:
abort(400)
t.task_title = request.json['title']
if 'description' in request.json:
if type(request.json['description']) != unicode:
abort(400)
t.task_description = request.json['description']
if 'done' in request.json:
if type(request.json['done']) is not bool:
abort(400)
t.task_completed = request.json['done']
db.session.commit()
# Return status code 200, with body being ID updated
return jsonify(to_dict(t)), 200
@app.route('/todo/api2/v1.0/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
"""Remove task from db."""
t = Tasks.query.get_or_404(task_id)
t.delete()
db.session.commit()
return jsonify(""), 200
@app.errorhandler(404)
def not_found(error):
"""Return json for 404 error"""
return make_response(jsonify({'error': 'Not found'}), 404)
### HELPER FUNCTION ###
def to_dict(task):
"""Turn an employee object into a dictionary."""
return {
'id': task.task_id,
'title': task.task_title,
'description': task.task_description,
'completed': task.task_completed,
'uri': url_for('get_task', task_id=task.task_id, _external=True)
}
if __name__ == '__main__':
connect_to_db(app)
manager = APIManager(app, flask_sqlalchemy_db=db)
# Create API endpoints, which will be available at /api/<tablename> by
# default. Allowed HTTP methods can be specified as well.
manager.create_api(
Tasks,
methods=['GET', 'POST', 'DELETE', 'PUT', 'PATCH'])
app.run(debug=True)