Add CORS headers in the API response, add a debug option to get verbose debugging from Bottle webserver
This commit is contained in:
parent
8a74a79ac2
commit
03d2ad6f7f
@ -233,4 +233,5 @@ def serve(config):
|
||||
# standard logging
|
||||
server = web_app.QuietWSGIRefServer
|
||||
|
||||
app.run(host=config["host"], port=config["port"], server=server)
|
||||
app.run(host=config["host"], port=config["port"], server=server,
|
||||
debug=config["debug"])
|
||||
|
@ -63,6 +63,8 @@ DEFAULT_CONFIG = {
|
||||
"search_index": None,
|
||||
# Web app port
|
||||
"port": 8080,
|
||||
# Debug mode for webserver
|
||||
"debug": False,
|
||||
# Web app host to listen on
|
||||
"host": "127.0.0.1",
|
||||
# Web server to use to serve the webapp (see Bottle deployment doc)
|
||||
@ -126,6 +128,7 @@ def validate_config(config, check_with_data):
|
||||
|
||||
assert config["database"] is None or isinstance(config["database"], str) # noqa: E501
|
||||
|
||||
assert isinstance(config["debug"], bool)
|
||||
assert isinstance(config["port"], int)
|
||||
assert isinstance(config["host"], str)
|
||||
assert config["webserver"] is None or isinstance(config["webserver"], str) # noqa: E501
|
||||
|
@ -42,7 +42,6 @@ def _serve_static_file(filename):
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_app(config):
|
||||
"""
|
||||
Get a Bottle app instance with all the routes set-up.
|
||||
@ -51,7 +50,7 @@ def get_app(config):
|
||||
"""
|
||||
get_session = database.init_db(config["database"], config["search_index"])
|
||||
|
||||
app = bottle.default_app()
|
||||
app = bottle.Bottle()
|
||||
app.install(DatabasePlugin(get_session))
|
||||
app.install(ConfigPlugin(config))
|
||||
app.config.setdefault("canister.log_level", logging.root.level)
|
||||
@ -60,24 +59,40 @@ def get_app(config):
|
||||
app.install(canister.Canister())
|
||||
# Use DateAwareJSONEncoder to dump JSON strings
|
||||
# From http://stackoverflow.com/questions/21282040/bottle-framework-how-to-return-datetime-in-json-response#comment55718456_21282666. pylint: disable=locally-disabled,line-too-long
|
||||
bottle.install(
|
||||
app.install(
|
||||
bottle.JSONPlugin(
|
||||
json_dumps=functools.partial(json.dumps, cls=DateAwareJSONEncoder)
|
||||
)
|
||||
)
|
||||
|
||||
# API v1 routes
|
||||
app.route("/api/v1/", "GET", api_routes.index_v1)
|
||||
# Enable CORS
|
||||
@app.hook('after_request')
|
||||
def enable_cors():
|
||||
"""
|
||||
Add CORS headers at each request.
|
||||
"""
|
||||
# The str() call is required as we import unicode_literal and WSGI
|
||||
# headers list should have plain str type.
|
||||
bottle.response.headers[str('Access-Control-Allow-Origin')] = '*'
|
||||
bottle.response.headers[str('Access-Control-Allow-Methods')] = (
|
||||
'PUT, GET, POST, DELETE, OPTIONS'
|
||||
)
|
||||
bottle.response.headers[str('Access-Control-Allow-Headers')] = (
|
||||
'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
|
||||
)
|
||||
|
||||
app.route("/api/v1/time_to_places", "GET",
|
||||
# API v1 routes
|
||||
app.route("/api/v1/", ["GET", "OPTIONS"], api_routes.index_v1)
|
||||
|
||||
app.route("/api/v1/time_to_places", ["GET", "OPTIONS"],
|
||||
api_routes.time_to_places_v1)
|
||||
|
||||
app.route("/api/v1/flats", "GET", api_routes.flats_v1)
|
||||
app.route("/api/v1/flats/:flat_id", "GET", api_routes.flat_v1)
|
||||
app.route("/api/v1/flats/:flat_id", "PATCH",
|
||||
app.route("/api/v1/flats", ["GET", "OPTIONS"], api_routes.flats_v1)
|
||||
app.route("/api/v1/flats/:flat_id", ["GET", "OPTIONS"], api_routes.flat_v1)
|
||||
app.route("/api/v1/flats/:flat_id", ["PATCH", "OPTIONS"],
|
||||
api_routes.update_flat_v1)
|
||||
|
||||
app.route("/api/v1/ics/visits.ics", "GET",
|
||||
app.route("/api/v1/ics/visits.ics", ["GET", "OPTIONS"],
|
||||
api_routes.ics_feed_v1)
|
||||
|
||||
app.route("/api/v1/search", "POST", api_routes.search_v1)
|
||||
|
@ -103,6 +103,10 @@ def flats_v1(config, db):
|
||||
|
||||
:return: The available flats objects in a JSON ``data`` dict.
|
||||
"""
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
# CORS
|
||||
return ''
|
||||
|
||||
try:
|
||||
db_query = db.query(flat_model.Flat)
|
||||
|
||||
@ -139,6 +143,10 @@ def flat_v1(flat_id, config, db):
|
||||
|
||||
:return: The flat object in a JSON ``data`` dict.
|
||||
"""
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
# CORS
|
||||
return {}
|
||||
|
||||
try:
|
||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||
|
||||
@ -171,6 +179,10 @@ def update_flat_v1(flat_id, config, db):
|
||||
|
||||
:return: The new flat object in a JSON ``data`` dict.
|
||||
"""
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
# CORS
|
||||
return {}
|
||||
|
||||
try:
|
||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||
if not flat:
|
||||
@ -204,6 +216,10 @@ def time_to_places_v1(config):
|
||||
:return: The JSON dump of the places to compute time to (dict of places
|
||||
names mapped to GPS coordinates).
|
||||
"""
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
# CORS
|
||||
return {}
|
||||
|
||||
try:
|
||||
places = {}
|
||||
for constraint_name, constraint in config["constraints"].items():
|
||||
@ -231,6 +247,10 @@ def search_v1(db, config):
|
||||
|
||||
:return: The matching flat objects in a JSON ``data`` dict.
|
||||
"""
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
# CORS
|
||||
return {}
|
||||
|
||||
try:
|
||||
try:
|
||||
query = json.load(bottle.request.body)["query"]
|
||||
@ -260,6 +280,10 @@ def ics_feed_v1(config, db):
|
||||
|
||||
:return: The ICS feed for the visits.
|
||||
"""
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
# CORS
|
||||
return {}
|
||||
|
||||
cal = vobject.iCalendar()
|
||||
try:
|
||||
flats_with_visits = db.query(flat_model.Flat).filter(
|
||||
|
Loading…
Reference in New Issue
Block a user