"""Handlers. ============================== Requests are redirected to handlers, which are responsible for getting information from the URL and passing it down to the logic layer. The way each layer talks to each other is through Response objects which defines the type status of the data and the data itself. Please note: the Orchard uses the term handlers over views as convention for clarity See: territories.response for more details. """ from flask import g from flask import jsonify from flask import request from territories import config from territories import response from territories.api import app from territories.logic import territories from territories.util import handler_util from territories.validation import validators @app.route(config.HEALTH_CHECK) def health(): """Check the health of the application.""" return jsonify({'status': 'ok'}) @app.route('/standards') @handler_util.validate_header(validators.HEADER_VALIDATOR) def get_standards(): """Get all supported standards. Returns: flask.Response: A 200 response with JSON payload containing list of all standards, supported by the service. """ log_message = 'GET /standards' g.log.info(log_message) result = territories.get_standards() return response.flaskify(result) @app.route('/territory/') @handler_util.validate_header(validators.HEADER_VALIDATOR) def get_territories(standard): """Get all territories in requested standard. Args: standard (str): one of the supported standards Returns: flask.Response: A 200 response with JSON payload containing list of territories for a given standard. """ log_message = f'GET /territory/(standard): standard={standard}; ' g.log.info(log_message) result = territories.get_territories(standard) headers = {'Cache-Control': 'max-age=86400'} return response.flaskify(result, headers) @app.route('/conversion//') @handler_util.validate_header(validators.HEADER_VALIDATOR) def convert_territories(input_standard, output_standard): """Get converted countries given source and target standard. Request parameters: territory_code_a2 (str): comma-separated list of territories Args: input_standard: standard to convert from output_standard: standard to convert to Returns: flask.Response: A 200 response with JSON payload containing list of converted countries. """ territory_codes = request.args.get('territory_code_a2', '') log_message = ( 'GET /conversion/(input_standard)/(output_standard): ' 'input_standard={};' 'output_standard={};' 'territory_code_a2={}').format( input_standard, output_standard, territory_codes) g.log.info(log_message) result = territories.convert_territories( input_standard, output_standard, territory_codes.split(',')) return response.flaskify(result) @app.route('/complement/') @handler_util.validate_header(validators.HEADER_VALIDATOR) def get_complement_territories(standard): """Get inverted countries list. Request parameters: territory_code_a2 (str): comma-separated list of territories Args: standard (str): standard name Returns: flask.Response: list of territories complement to the given input. Please note, that the response can contain empty list, in cases when input list contains full set of countries of a given standard. """ territory_codes = request.args.get('territory_code_a2', '') log_message = ( 'GET /complement/(standard): ' 'standard={};' 'territory_code_a2={}').format(standard, territory_codes) g.log.info(log_message) territories_list = territory_codes.split(',') if territory_codes else [] result = territories.get_complement(standard, territories_list) return response.flaskify(result) @app.errorhandler(500) def exception_handler(error): """Handle uncaught exception. Note: Exception will also be sent to Sentry if config.SENTRY_DSN is set. Returns: flask.Response: A 500 response with JSON 'code' & 'message' payload. """ message = ( 'The server encountered an internal error ' 'and was unable to complete your request.') g.log.exception(error) return response.flaskify(response.create_fatal_response(message))