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.
This commit is contained in:
Fabio Manganiello 2022-09-01 01:37:18 +02:00
parent 96b2ad148c
commit c5b12403d0
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 39 additions and 6 deletions

View file

@ -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))

View file

@ -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)