-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
246 lines (195 loc) · 6.97 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
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
import os
from http import HTTPStatus
from dotenv import load_dotenv
from flask import Flask, jsonify, request, abort
from flask_cors import CORS
from auth import requires_auth, AuthError
from models import setup_db, Actor, GenderEnum, Movie
load_dotenv()
def create_app(config=os.environ['APP_SETTINGS']):
# create and configure the app
app = Flask(__name__)
# setup using one of the config modules in config.py
# create a APP_SETTINGS variable in .env file such as
# APP_SETTINGS=config.DevelopmentConfig
app.config.from_object(config)
setup_db(app)
# Set up CORS. Allow '*' for origins.
CORS(app, resources={r"*": {"origins": "*"}})
# Use the after_request decorator to set Access-Control-Allow
@app.after_request
def after_request(response):
response.headers.add("Access-Control-Allow-Headers",
"Content-Type,Authorization,true")
response.headers.add("Access-Control-Allow-Methods",
"GET,PATCH,POST,DELETE,OPTIONS")
return response
@app.route('/')
def default_route():
"""
Just to test app is running
"""
return 'Welcome to Agency'
# Helper functions
def serialize_list(model_list: list):
"""
Each model should have a serialize attribute
To return the data to the frontend serialized this function should be called
to serialize a list of models
"""
return [i.serialize for i in model_list]
# Actor Routes
@app.route('/actors', methods=['GET'])
@requires_auth(permission='get:actors')
def get_actors():
actors = Actor.query.all()
actors_serialized = serialize_list(actors)
return jsonify({"actors": actors_serialized}), HTTPStatus.OK
@app.route('/actors', methods=['POST'])
@requires_auth(permission='post:actors')
def post_actor():
json = request.get_json()
name = json.get("name")
age = int(json.get("age"))
gender = json.get("gender")
# make sure all required data is present, else -> 400 error response
if name is None or age is None or gender is None:
abort(HTTPStatus.BAD_REQUEST)
# create new question and add commit to the db
actor = Actor(name=name, age=age, gender=gender)
actor.insert()
return jsonify(success=True), HTTPStatus.OK
@app.route('/actors/<int:key>', methods=['DELETE'])
@requires_auth(permission='delete:actors')
def delete_actor(key: int):
actor = Actor.query.get_or_404(key)
actor.delete()
return jsonify(success=True), HTTPStatus.OK
@app.route('/actors/<int:key>', methods=['PATCH'])
@requires_auth(permission='patch:actors')
def patch_actor(key: int):
json = request.get_json()
actor = Actor.query.get_or_404(key)
name = json.get("name")
if name is not None:
actor.name = name
age = json.get("age")
if age is not None:
actor.age = age
gender = json.get("gender")
if gender is not None:
actor.gender = GenderEnum.transform(gender)
actor.update()
return jsonify(success=True), HTTPStatus.OK
# Movie handlers
@app.route('/movies', methods=['GET'])
@requires_auth(permission='get:movies')
def get_movies():
movies = Movie.query.all()
movies_serialized = serialize_list(movies)
return jsonify({"movies": movies_serialized}), HTTPStatus.OK
@app.route('/movies', methods=['POST'])
@requires_auth(permission='post:movies')
def post_movie():
json = request.get_json()
title = json.get("title")
# make sure all required data is present, else -> 400 error response
if title is None:
abort(HTTPStatus.BAD_REQUEST)
# create new question and add commit to the db
movie = Movie(title=title)
movie.insert()
return jsonify(success=True), HTTPStatus.OK
@app.route('/movies/<int:key>', methods=['DELETE'])
@requires_auth(permission='delete:movies')
def delete_movie(key: int):
movie = Movie.query.get_or_404(key)
movie.delete()
return jsonify(success=True), HTTPStatus.OK
@app.route('/movies/<int:key>', methods=['PATCH'])
@requires_auth(permission='patch:movies')
def patch_movie(key: int):
json = request.get_json()
movie = Movie.query.get_or_404(key)
title = json.get("title")
if title is not None:
movie.title = title
movie.update()
return jsonify(success=True), HTTPStatus.OK
# Error handlers
@app.errorhandler(AuthError)
def auth_error_handler(e: AuthError):
return (
jsonify(
{
"success": False,
"error": e.status_code,
"message": e.error.get("description"),
}
),
e.status_code,
)
@app.errorhandler(HTTPStatus.BAD_REQUEST)
def bad_request_400(error):
return (
jsonify(
{
"success": False,
"error": HTTPStatus.BAD_REQUEST,
"message": HTTPStatus.BAD_REQUEST.phrase,
}
),
HTTPStatus.BAD_REQUEST,
)
@app.errorhandler(HTTPStatus.UNAUTHORIZED)
def unauthorized_401(error):
return (
jsonify(
{
"success": False,
"error": HTTPStatus.UNAUTHORIZED,
"message": HTTPStatus.UNAUTHORIZED.phrase,
}
),
HTTPStatus.UNAUTHORIZED,
)
@app.errorhandler(HTTPStatus.NOT_FOUND)
def not_found_404(error):
return (
jsonify(
{
"success": False,
"error": HTTPStatus.NOT_FOUND,
"message": HTTPStatus.NOT_FOUND.phrase,
}
),
HTTPStatus.NOT_FOUND,
)
@app.errorhandler(HTTPStatus.UNPROCESSABLE_ENTITY)
def unprocessable_entity_422(error):
return (
jsonify(
{
"success": False,
"error": HTTPStatus.UNPROCESSABLE_ENTITY,
"message": HTTPStatus.UNPROCESSABLE_ENTITY.phrase,
}
),
HTTPStatus.UNPROCESSABLE_ENTITY,
)
@app.errorhandler(HTTPStatus.INTERNAL_SERVER_ERROR)
def internal_server_error_500(error):
return (
jsonify(
{
"success": False,
"error": HTTPStatus.INTERNAL_SERVER_ERROR,
"message": HTTPStatus.INTERNAL_SERVER_ERROR.phrase,
}
),
HTTPStatus.INTERNAL_SERVER_ERROR,
)
return app
APP = create_app(config=os.environ['APP_SETTINGS'])
if __name__ == '__main__':
APP.run(host='0.0.0.0', port=8080, debug=True)