Skip to content

Commit

Permalink
Merge pull request #227 from DHI-GRAS/flask-error-handlers
Browse files Browse the repository at this point in the history
Use Flask error handlers instead of decorators (#74)
  • Loading branch information
j08lue authored Aug 6, 2021
2 parents 7d35ab8 + 2b90eeb commit 1037297
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 46 deletions.
3 changes: 1 addition & 2 deletions terracotta/server/colormap.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from flask import jsonify, request, Response
from marshmallow import Schema, fields, validate, pre_load, ValidationError, EXCLUDE

from terracotta.server.flask_api import convert_exceptions, METADATA_API
from terracotta.server.flask_api import METADATA_API
from terracotta.cmaps import AVAILABLE_CMAPS


Expand Down Expand Up @@ -52,7 +52,6 @@ def process_ranges(self, data: Mapping[str, Any], **kwargs: Any) -> Dict[str, An


@METADATA_API.route('/colormap', methods=['GET'])
@convert_exceptions
def get_colormap() -> Response:
"""Get a colormap mapping pixel values to colors
---
Expand Down
4 changes: 1 addition & 3 deletions terracotta/server/compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
pre_load, ValidationError, EXCLUDE)
from flask import request, send_file, Response

from terracotta.server.flask_api import convert_exceptions, TILE_API
from terracotta.server.flask_api import TILE_API
from terracotta.cmaps import AVAILABLE_CMAPS


Expand Down Expand Up @@ -75,7 +75,6 @@ def decode_json(self, data: Mapping[str, Any], **kwargs: Any) -> Dict[str, Any]:
@TILE_API.route('/compute/<int:tile_z>/<int:tile_x>/<int:tile_y>.png', methods=['GET'])
@TILE_API.route('/compute/<path:keys>/<int:tile_z>/<int:tile_x>/<int:tile_y>.png',
methods=['GET'])
@convert_exceptions
def get_compute(tile_z: int, tile_y: int, tile_x: int, keys: str = '') -> Response:
"""Combine datasets into a single-band PNG image through a given mathematical expression
---
Expand Down Expand Up @@ -109,7 +108,6 @@ class ComputePreviewSchema(Schema):

@TILE_API.route('/compute/preview.png', methods=['GET'])
@TILE_API.route('/compute/<path:keys>/preview.png', methods=['GET'])
@convert_exceptions
def get_compute_preview(keys: str = '') -> Response:
"""Combine datasets into a single-band PNG image through a given mathematical expression
---
Expand Down
3 changes: 1 addition & 2 deletions terracotta/server/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from flask import request, jsonify, Response
from marshmallow import Schema, fields, validate, INCLUDE

from terracotta.server.flask_api import convert_exceptions, METADATA_API
from terracotta.server.flask_api import METADATA_API


class DatasetOptionSchema(Schema):
Expand Down Expand Up @@ -42,7 +42,6 @@ class Meta:


@METADATA_API.route('/datasets', methods=['GET'])
@convert_exceptions
def get_datasets() -> Response:
"""Get all available key combinations
---
Expand Down
54 changes: 25 additions & 29 deletions terracotta/server/flask_api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from typing import Callable, Any
import functools
from typing import Any
import copy

from apispec import APISpec
Expand Down Expand Up @@ -34,40 +33,35 @@
)


def abort(status_code: int, message: str = '') -> Any:
def _abort(status_code: int, message: str = '') -> Any:
response = jsonify({'message': message})
response.status_code = status_code
return response


def convert_exceptions(fun: Callable) -> Callable:
"""Converts internal exceptions to appropriate HTTP responses"""
def _setup_error_handlers(app: Flask) -> None:
@app.errorhandler(exceptions.TileOutOfBoundsError)
def handle_tile_out_of_bounds_error(exc: Exception) -> Any:
# send empty image
from terracotta import get_settings, image
settings = get_settings()
return send_file(image.empty_image(settings.DEFAULT_TILE_SIZE), mimetype='image/png')

@functools.wraps(fun)
def inner(*args: Any, **kwargs: Any) -> Any:
try:
return fun(*args, **kwargs)
@app.errorhandler(exceptions.DatasetNotFoundError)
def handle_dataset_not_found_error(exc: Exception) -> Any:
# wrong path -> 404
if current_app.debug:
raise exc
return _abort(404, str(exc))

except exceptions.TileOutOfBoundsError:
# send empty image
from terracotta import get_settings, image
settings = get_settings()
return send_file(image.empty_image(settings.DEFAULT_TILE_SIZE), mimetype='image/png')

except exceptions.DatasetNotFoundError as exc:
# wrong path -> 404
if current_app.debug:
raise
return abort(404, str(exc))

except (exceptions.InvalidArgumentsError, exceptions.InvalidKeyError,
marshmallow.ValidationError) as exc:
# wrong query arguments -> 400
if current_app.debug:
raise
return abort(400, str(exc))

return inner
@app.errorhandler(exceptions.InvalidArgumentsError)
@app.errorhandler(exceptions.InvalidKeyError)
@app.errorhandler(marshmallow.ValidationError)
def handle_marshmallow_validation_error(exc: Exception) -> Any:
# wrong query arguments -> 400
if current_app.debug:
raise exc
return _abort(400, str(exc))


def create_app(debug: bool = False, profile: bool = False) -> Flask:
Expand Down Expand Up @@ -124,4 +118,6 @@ def create_app(debug: bool = False, profile: bool = False) -> Flask:
ProfilerMiddleware(new_app.wsgi_app, restrictions=[30])
)

_setup_error_handlers(new_app)

return new_app
3 changes: 1 addition & 2 deletions terracotta/server/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from flask import jsonify, Response
from marshmallow import Schema, fields

from terracotta.server.flask_api import convert_exceptions, METADATA_API
from terracotta.server.flask_api import METADATA_API


class KeyItemSchema(Schema):
Expand All @@ -22,7 +22,6 @@ class KeySchema(Schema):


@METADATA_API.route('/keys', methods=['GET'])
@convert_exceptions
def get_keys() -> Response:
"""Get all key names
---
Expand Down
3 changes: 1 addition & 2 deletions terracotta/server/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from marshmallow import Schema, fields, validate
from flask import jsonify, Response

from terracotta.server.flask_api import convert_exceptions, METADATA_API
from terracotta.server.flask_api import METADATA_API


class MetadataSchema(Schema):
Expand All @@ -30,7 +30,6 @@ class Meta:


@METADATA_API.route('/metadata/<path:keys>', methods=['GET'])
@convert_exceptions
def get_metadata(keys: str) -> Response:
"""Get metadata for given dataset
---
Expand Down
4 changes: 1 addition & 3 deletions terracotta/server/rgb.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from marshmallow import Schema, fields, validate, pre_load, ValidationError, EXCLUDE
from flask import request, send_file, Response

from terracotta.server.flask_api import convert_exceptions, TILE_API
from terracotta.server.flask_api import TILE_API


class RGBQuerySchema(Schema):
Expand Down Expand Up @@ -58,7 +58,6 @@ def process_ranges(self, data: Mapping[str, Any], **kwargs: Any) -> Dict[str, An

@TILE_API.route('/rgb/<int:tile_z>/<int:tile_x>/<int:tile_y>.png', methods=['GET'])
@TILE_API.route('/rgb/<path:keys>/<int:tile_z>/<int:tile_x>/<int:tile_y>.png', methods=['GET'])
@convert_exceptions
def get_rgb(tile_z: int, tile_y: int, tile_x: int, keys: str = '') -> Response:
"""Return the requested RGB tile as a PNG image.
---
Expand Down Expand Up @@ -91,7 +90,6 @@ class RGBPreviewQuerySchema(Schema):

@TILE_API.route('/rgb/preview.png', methods=['GET'])
@TILE_API.route('/rgb/<path:keys>/preview.png', methods=['GET'])
@convert_exceptions
def get_rgb_preview(keys: str = '') -> Response:
"""Return the requested RGB dataset preview as a PNG image.
---
Expand Down
4 changes: 1 addition & 3 deletions terracotta/server/singleband.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
pre_load, ValidationError, EXCLUDE)
from flask import request, send_file, Response

from terracotta.server.flask_api import convert_exceptions, TILE_API
from terracotta.server.flask_api import TILE_API
from terracotta.cmaps import AVAILABLE_CMAPS


Expand Down Expand Up @@ -94,7 +94,6 @@ def decode_json(self, data: Mapping[str, Any], **kwargs: Any) -> Dict[str, Any]:

@TILE_API.route('/singleband/<path:keys>/<int:tile_z>/<int:tile_x>/<int:tile_y>.png',
methods=['GET'])
@convert_exceptions
def get_singleband(tile_z: int, tile_y: int, tile_x: int, keys: str) -> Response:
"""Return single-band PNG image of requested tile
---
Expand Down Expand Up @@ -126,7 +125,6 @@ class SinglebandPreviewSchema(Schema):


@TILE_API.route('/singleband/<path:keys>/preview.png', methods=['GET'])
@convert_exceptions
def get_singleband_preview(keys: str) -> Response:
"""Return single-band PNG preview image of requested dataset
---
Expand Down

0 comments on commit 1037297

Please sign in to comment.