From c5b12403d01ff81cee41753e41c1b73d7d69a839 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Thu, 1 Sep 2022 01:37:18 +0200 Subject: [PATCH] Implemented support for returning richer HTTP responses on webhooks. A `WebhookEvent` hook can now return a tuple in the format `(data, http_code, headers)` in order to customize the HTTP status code and the headers of a response. --- platypush/backend/http/app/routes/hook.py | 28 ++++++++++++++++++----- platypush/message/event/http/hook.py | 17 ++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/platypush/backend/http/app/routes/hook.py b/platypush/backend/http/app/routes/hook.py index 6996fcad7..5d9b420cc 100644 --- a/platypush/backend/http/app/routes/hook.py +++ b/platypush/backend/http/app/routes/hook.py @@ -1,7 +1,6 @@ import json -from flask import Blueprint, abort, request -from flask.wrappers import Response +from flask import Blueprint, abort, request, make_response from platypush.backend.http.app import template_folder from platypush.backend.http.app.utils import logger, send_message @@ -61,14 +60,31 @@ def hook_route(hook_name): try: send_message(event) + rs = make_response(json.dumps({'status': 'ok', **event_args})) + headers = {} + status_code = 200 # If there are matching hooks, wait for their completion before returning if matching_hooks: - return event.wait_response(timeout=60) + rs = event.wait_response(timeout=60) + try: + rs = json.loads(rs.decode()) # type: ignore + except Exception: + pass - return Response( - json.dumps({'status': 'ok', **event_args}), mimetype='application/json' - ) + if isinstance(rs, dict) and '___data___' in rs: + # data + http_code + custom_headers return format + headers = rs.get('___headers___', {}) + status_code = rs.get('___code___', status_code) + rs = rs['___data___'] + + rs = make_response(rs) + else: + headers = {'Content-Type': 'application/json'} + + rs.status_code = status_code + rs.headers.update(headers) + return rs except Exception as e: logger().exception(e) logger().error('Error while dispatching webhook event %s: %s', event, str(e)) diff --git a/platypush/message/event/http/hook.py b/platypush/message/event/http/hook.py index 728a13c57..e6f386100 100644 --- a/platypush/message/event/http/hook.py +++ b/platypush/message/event/http/hook.py @@ -58,6 +58,23 @@ class WebhookEvent(Event): def send_response(self, response): output = response.output + if isinstance(output, tuple): + # A 3-sized tuple where the second element is an int and the third + # is a dict represents an HTTP response in the format `(data, + # http_code headers)`. + if ( + len(output) == 3 + and isinstance(output[1], int) + and isinstance(output[2], dict) + ): + output = { + '___data___': output[0], + '___code___': output[1], + '___headers___': output[2], + } + else: + # Normalize tuples to lists before serialization + output = list(output) if isinstance(output, (dict, list)): output = json.dumps(output)