diff --git a/templates/zerver/api/webhook-walkthrough.md b/templates/zerver/api/webhook-walkthrough.md index e74c23eb27..77a1ecc051 100644 --- a/templates/zerver/api/webhook-walkthrough.md +++ b/templates/zerver/api/webhook-walkthrough.md @@ -535,3 +535,18 @@ be running an older version of the integration that doesn't set that header. If the requisite header is missing, this function sends a PM to the owner of the webhook bot, notifying them of the missing header. + +### Handling unexpected webhook event types + +Many third-party services have dozens of different event types. In some cases, we +may choose to explicitly ignore specific events. In other cases, there may be +events that are new or events that we don't know about. In such cases, we +recommend raising `UnexpectedWebhookEventType` (found in +`zerver/lib/webhooks/common.py`), like so: + +``` +raise UnexpectedWebhookEventType(webhook_name, event_type) +``` + +`webhook_name` is the name of the webhook that raises the exception. `event_type` +is the name of the unexpected webhook event. diff --git a/tools/coveragerc b/tools/coveragerc index c40742af69..e62bb057ca 100644 --- a/tools/coveragerc +++ b/tools/coveragerc @@ -11,6 +11,8 @@ exclude_lines = raise AssertionError # Don't require coverage for __str__ statements just used for printing def __str__[(]self[)] -> .*: + # Don't require coverage for errors about unsupported webhook event types + raise UnexpectedWebhookEventType [run] omit = diff --git a/zerver/lib/exceptions.py b/zerver/lib/exceptions.py index 7ce202bfe3..8dc538cc55 100644 --- a/zerver/lib/exceptions.py +++ b/zerver/lib/exceptions.py @@ -34,6 +34,7 @@ class ErrorCode(AbstractEnum): MISSING_HTTP_EVENT_HEADER = () STREAM_DOES_NOT_EXIST = () UNAUTHORIZED_PRINCIPAL = () + UNEXPECTED_WEBHOOK_EVENT_TYPE = () BAD_EVENT_QUEUE_ID = () CSRF_FAILED = () INVITATION_FAILED = () diff --git a/zerver/lib/webhooks/common.py b/zerver/lib/webhooks/common.py index 39829b8388..2232e401ea 100644 --- a/zerver/lib/webhooks/common.py +++ b/zerver/lib/webhooks/common.py @@ -24,6 +24,18 @@ Contact {support_email} if you need help debugging! # Django prefixes all custom HTTP headers with `HTTP_` DJANGO_HTTP_PREFIX = "HTTP_" +class UnexpectedWebhookEventType(JsonableError): + code = ErrorCode.UNEXPECTED_WEBHOOK_EVENT_TYPE + data_fields = ['webhook_name', 'event_type'] + + def __init__(self, webhook_name: str, event_type: Optional[str]) -> None: + self.webhook_name = webhook_name + self.event_type = event_type + + @staticmethod + def msg_format() -> str: + return _("The '{event_type}' event isn't currently supported by the {webhook_name} webhook") + class MissingHTTPEventHeader(JsonableError): code = ErrorCode.MISSING_HTTP_EVENT_HEADER data_fields = ['header']