From 1802c3cf4d44473153b7221bcdc391a3f7fb6a92 Mon Sep 17 00:00:00 2001 From: pmontens Date: Mon, 25 Nov 2019 11:57:48 +0100 Subject: [PATCH 1/2] Added blueprint json route to serialize and tag content-type correctly --- labonneboite/web/search/views.py | 44 +++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/labonneboite/web/search/views.py b/labonneboite/web/search/views.py index 0a739b4bc..f646bc6b9 100644 --- a/labonneboite/web/search/views.py +++ b/labonneboite/web/search/views.py @@ -1,6 +1,7 @@ from urllib.parse import urlencode import json +import types from slugify import slugify @@ -30,21 +31,40 @@ searchBlueprint = Blueprint('search', __name__) -@searchBlueprint.route('/suggest_job_labels') +def js_route(self, rule, **options): + def decorator(function): + endpoint = options.pop("endpoint", function.__name__) + + def decorated_function(*args, **kwargs): + raw_response = function(*args, **kwargs) + response = make_response(json.dumps(raw_response)) + response.mimetype = 'application/json' + return response + + self.add_url_rule(rule, endpoint, decorated_function, **options) + + return decorated_function + return decorator + + +searchBlueprint.js_route = types.MethodType(js_route, searchBlueprint) + + +@searchBlueprint.js_route('/suggest_job_labels') def suggest_job_labels(): term = request.args.get('term', '') suggestions = autocomplete.build_job_label_suggestions(term) - return make_response(json.dumps(suggestions)) + return suggestions -@searchBlueprint.route('/suggest_locations') +@searchBlueprint.js_route('/suggest_locations') def suggest_locations(): term = request.args.get('term', '') suggestions = autocomplete.build_location_suggestions(term) - return make_response(json.dumps(suggestions)) + return suggestions -@searchBlueprint.route('/autocomplete/locations') +@searchBlueprint.js_route('/autocomplete/locations') def autocomplete_locations(): """ Query string arguments: @@ -61,10 +81,10 @@ def autocomplete_locations(): pass # FIXME log BAN LIKELY DOWN event for suggestion in suggestions: suggestion['value'] = suggestion['label'] - return make_response(json.dumps(suggestions)) + return suggestions -@searchBlueprint.route('/job_slug_details') +@searchBlueprint.js_route('/job_slug_details') def job_slug_details(): result = [] @@ -82,10 +102,10 @@ def job_slug_details(): 'label': settings.ROME_DESCRIPTIONS.get(rome, ''), }) - return make_response(json.dumps(result)) + return result -@searchBlueprint.route('/city_slug_details') +@searchBlueprint.js_route('/city_slug_details') def city_slug_details(): """ Endpoint used by La Bonne Alternance only. @@ -113,10 +133,10 @@ def city_slug_details(): 'longitude': city_location.location.longitude, 'latitude': city_location.location.latitude, } - return make_response(json.dumps(result)) + return result -@searchBlueprint.route('/city_code_details') +@searchBlueprint.js_route('/city_code_details') def city_code_details(): """ Endpoint used by La Bonne Alternance only. @@ -140,7 +160,7 @@ def city_code_details(): 'latitude': city['coords']['lat'], } - return make_response(json.dumps(result)) + return result PARAMETER_FIELD_MAPPING = { From a4aa7d95037dd07f3940527f5e3c59ef196464d7 Mon Sep 17 00:00:00 2001 From: pmontens Date: Mon, 25 Nov 2019 12:17:31 +0100 Subject: [PATCH 2/2] improving naming, added docstring --- labonneboite/web/search/views.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/labonneboite/web/search/views.py b/labonneboite/web/search/views.py index f646bc6b9..f98ddb1b6 100644 --- a/labonneboite/web/search/views.py +++ b/labonneboite/web/search/views.py @@ -3,6 +3,7 @@ import json import types +from functools import wraps from slugify import slugify from flask import abort, make_response, redirect, render_template, request, session, url_for @@ -32,18 +33,27 @@ def js_route(self, rule, **options): + """ + Alternative Bleuprint route, specifically for json responses. + Wether this approach is preferable to a simple decorator is debatable, + but it's probably the less obtrusive one. + + The decorator factory creates wrappers able to serialize the raw + json output and prepare a response with the right json mimetype. + """ def decorator(function): endpoint = options.pop("endpoint", function.__name__) - def decorated_function(*args, **kwargs): + @wraps(function) + def wrapper(*args, **kwargs): raw_response = function(*args, **kwargs) response = make_response(json.dumps(raw_response)) response.mimetype = 'application/json' return response - self.add_url_rule(rule, endpoint, decorated_function, **options) + self.add_url_rule(rule, endpoint, wrapper, **options) - return decorated_function + return wrapper return decorator