django-webhook-subscriber 2.0.0__py3-none-any.whl → 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_webhook_subscriber/delivery.py +15 -9
- django_webhook_subscriber/serializers.py +13 -0
- django_webhook_subscriber/tests/test_delivery.py +72 -0
- {django_webhook_subscriber-2.0.0.dist-info → django_webhook_subscriber-2.1.0.dist-info}/METADATA +49 -1
- {django_webhook_subscriber-2.0.0.dist-info → django_webhook_subscriber-2.1.0.dist-info}/RECORD +8 -8
- {django_webhook_subscriber-2.0.0.dist-info → django_webhook_subscriber-2.1.0.dist-info}/WHEEL +1 -1
- {django_webhook_subscriber-2.0.0.dist-info → django_webhook_subscriber-2.1.0.dist-info}/licenses/LICENSE +0 -0
- {django_webhook_subscriber-2.0.0.dist-info → django_webhook_subscriber-2.1.0.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,7 @@ from django.utils import timezone
|
|
|
8
8
|
from django.utils.module_loading import import_string
|
|
9
9
|
|
|
10
10
|
from .conf import rest_webhook_settings as settings
|
|
11
|
-
from .serializers import serialize_webhook_instance
|
|
11
|
+
from .serializers import WebhookRawPayloadMixin, serialize_webhook_instance
|
|
12
12
|
from .tasks import process_webhook_delivery_batch
|
|
13
13
|
from .utils import (
|
|
14
14
|
clear_content_type_cache,
|
|
@@ -184,14 +184,20 @@ class WebhookDeliveryProcessor:
|
|
|
184
184
|
)
|
|
185
185
|
|
|
186
186
|
# Build standard payload structure
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
187
|
+
if serializer_class and issubclass(
|
|
188
|
+
serializer_class, WebhookRawPayloadMixin
|
|
189
|
+
):
|
|
190
|
+
# Raw payload mixin - use fields data directly
|
|
191
|
+
payload = fields_data
|
|
192
|
+
else:
|
|
193
|
+
payload = {
|
|
194
|
+
"pk": instance.pk,
|
|
195
|
+
"event_signal": event_name,
|
|
196
|
+
"source": f"{instance._meta.app_label}."
|
|
197
|
+
f"{instance._meta.model_name}",
|
|
198
|
+
"timestamp": timezone.now().isoformat(),
|
|
199
|
+
"fields": fields_data,
|
|
200
|
+
}
|
|
195
201
|
|
|
196
202
|
return payload
|
|
197
203
|
|
|
@@ -39,3 +39,16 @@ def serialize_webhook_instance(instance, field_serializer=None):
|
|
|
39
39
|
serialized_data = serializer.data
|
|
40
40
|
# Return the serialized data
|
|
41
41
|
return serialized_data
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class WebhookRawPayloadMixin:
|
|
45
|
+
"""
|
|
46
|
+
Mixin to indicate that the webhook payload should be sent as raw data.
|
|
47
|
+
|
|
48
|
+
By default, the payload includes extra fields and the serialized
|
|
49
|
+
instance data goes inside a 'fields' key.
|
|
50
|
+
By having this mixin, the webhook payload will be just the
|
|
51
|
+
serialized instance data.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
pass
|
|
@@ -220,6 +220,78 @@ class WebhookDeliveryProcessorTests(TestCase):
|
|
|
220
220
|
self.assertIn("error", result)
|
|
221
221
|
self.assertEqual(result["fields"], {})
|
|
222
222
|
|
|
223
|
+
@patch("django_webhook_subscriber.delivery.serialize_webhook_instance")
|
|
224
|
+
@patch("django_webhook_subscriber.delivery.import_string")
|
|
225
|
+
def test_generate_payload_with_raw_payload_mixin(
|
|
226
|
+
self, mock_import_string, mock_serialize
|
|
227
|
+
):
|
|
228
|
+
"""Test that WebhookRawPayloadMixin returns only serialized data."""
|
|
229
|
+
from rest_framework import serializers
|
|
230
|
+
|
|
231
|
+
from django_webhook_subscriber.serializers import (
|
|
232
|
+
WebhookRawPayloadMixin,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Create a serializer class with WebhookRawPayloadMixin
|
|
236
|
+
class RawPayloadSerializer(
|
|
237
|
+
WebhookRawPayloadMixin, serializers.ModelSerializer
|
|
238
|
+
):
|
|
239
|
+
class Meta:
|
|
240
|
+
model = models.WebhookDeliveryLog
|
|
241
|
+
fields = ["id", "payload"]
|
|
242
|
+
|
|
243
|
+
mock_import_string.return_value = RawPayloadSerializer
|
|
244
|
+
mock_serialize.return_value = {"id": 1, "payload": {"key": "value"}}
|
|
245
|
+
|
|
246
|
+
result = self.processor._generate_payload(
|
|
247
|
+
self.instance,
|
|
248
|
+
"created",
|
|
249
|
+
"some.path.RawPayloadSerializer",
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# With WebhookRawPayloadMixin, the payload should be the serialized
|
|
253
|
+
# data directly, without metadata wrapper
|
|
254
|
+
self.assertEqual(result, {"id": 1, "payload": {"key": "value"}})
|
|
255
|
+
self.assertNotIn("pk", result)
|
|
256
|
+
self.assertNotIn("event_signal", result)
|
|
257
|
+
self.assertNotIn("source", result)
|
|
258
|
+
self.assertNotIn("timestamp", result)
|
|
259
|
+
self.assertNotIn("fields", result)
|
|
260
|
+
|
|
261
|
+
@patch("django_webhook_subscriber.delivery.serialize_webhook_instance")
|
|
262
|
+
@patch("django_webhook_subscriber.delivery.import_string")
|
|
263
|
+
def test_generate_payload_without_raw_payload_mixin(
|
|
264
|
+
self, mock_import_string, mock_serialize
|
|
265
|
+
):
|
|
266
|
+
"""Test that regular serializers return payload with metadata."""
|
|
267
|
+
from rest_framework import serializers
|
|
268
|
+
|
|
269
|
+
# Create a regular serializer without WebhookRawPayloadMixin
|
|
270
|
+
class RegularSerializer(serializers.ModelSerializer):
|
|
271
|
+
class Meta:
|
|
272
|
+
model = models.WebhookDeliveryLog
|
|
273
|
+
fields = ["id", "payload"]
|
|
274
|
+
|
|
275
|
+
mock_import_string.return_value = RegularSerializer
|
|
276
|
+
mock_serialize.return_value = {"id": 1, "payload": {"key": "value"}}
|
|
277
|
+
|
|
278
|
+
result = self.processor._generate_payload(
|
|
279
|
+
self.instance,
|
|
280
|
+
"created",
|
|
281
|
+
"some.path.RegularSerializer",
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
# Without WebhookRawPayloadMixin, the payload should include metadata
|
|
285
|
+
self.assertEqual(result["pk"], 1)
|
|
286
|
+
self.assertEqual(result["event_signal"], "created")
|
|
287
|
+
self.assertEqual(
|
|
288
|
+
result["source"], "django_webhook_subscriber.webhookdeliverylog"
|
|
289
|
+
)
|
|
290
|
+
self.assertIn("timestamp", result)
|
|
291
|
+
self.assertEqual(
|
|
292
|
+
result["fields"], {"id": 1, "payload": {"key": "value"}}
|
|
293
|
+
)
|
|
294
|
+
|
|
223
295
|
def test_deliver_webhooks_on_no_subscriptions(self):
|
|
224
296
|
result = self.processor._deliver_webhooks([])
|
|
225
297
|
|
{django_webhook_subscriber-2.0.0.dist-info → django_webhook_subscriber-2.1.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-webhook-subscriber
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: A Django package designed to handle webhook creation, management, and delivery.
|
|
5
5
|
Author-email: 42 Portugal <root@42porto.com>
|
|
6
6
|
Classifier: Environment :: Web Environment
|
|
@@ -172,6 +172,53 @@ subscriber.serializer_class = "myapp.serializers.UserWebhookSerializer"
|
|
|
172
172
|
subscriber.save()
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
+
### 4. Raw Payload (No Metadata Wrapper)
|
|
176
|
+
|
|
177
|
+
By default, webhook payloads include metadata and the serialized data is nested inside a `fields` key:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"pk": 1,
|
|
182
|
+
"event_signal": "created",
|
|
183
|
+
"source": "auth.user",
|
|
184
|
+
"timestamp": "2026-02-05T10:30:00Z",
|
|
185
|
+
"fields": {
|
|
186
|
+
"id": 1,
|
|
187
|
+
"name": "John Doe",
|
|
188
|
+
"email": "john@example.com"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
If you prefer a raw payload containing only the serialized data (without the metadata wrapper), use the `WebhookRawPayloadMixin`:
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
from rest_framework import serializers
|
|
197
|
+
from django.contrib.auth import get_user_model
|
|
198
|
+
from django_webhook_subscriber.serializers import WebhookRawPayloadMixin
|
|
199
|
+
|
|
200
|
+
User = get_user_model()
|
|
201
|
+
|
|
202
|
+
class UserRawWebhookSerializer(WebhookRawPayloadMixin, serializers.ModelSerializer):
|
|
203
|
+
class Meta:
|
|
204
|
+
model = User
|
|
205
|
+
fields = ["id", "name", "email"]
|
|
206
|
+
|
|
207
|
+
# Update subscriber to use the raw payload serializer
|
|
208
|
+
subscriber.serializer_class = "myapp.serializers.UserRawWebhookSerializer"
|
|
209
|
+
subscriber.save()
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
With `WebhookRawPayloadMixin`, the webhook payload will be just the serialized data:
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"id": 1,
|
|
217
|
+
"name": "John Doe",
|
|
218
|
+
"email": "john@example.com"
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
175
222
|
## Configuration
|
|
176
223
|
|
|
177
224
|
Configure the package in your Django settings:
|
|
@@ -632,6 +679,7 @@ Set up cron jobs for maintenance:
|
|
|
632
679
|
```
|
|
633
680
|
|
|
634
681
|
3. **Monitor delivery performance:**
|
|
682
|
+
|
|
635
683
|
```bash
|
|
636
684
|
# Regular performance testing
|
|
637
685
|
python manage.py webhook_performance_test --model=myapp.User --event=test --object-count=10
|
{django_webhook_subscriber-2.0.0.dist-info → django_webhook_subscriber-2.1.0.dist-info}/RECORD
RENAMED
|
@@ -2,11 +2,11 @@ django_webhook_subscriber/__init__.py,sha256=t0izlsRXKHd46fRIwhDv8Cd59tb7MqAQ7DW
|
|
|
2
2
|
django_webhook_subscriber/admin.py,sha256=BGFV-1-wymm_qUsOlG0HBUY3rmAqKH59PbKaFEtAEI4,30100
|
|
3
3
|
django_webhook_subscriber/apps.py,sha256=U6GLuMB2xhtvUzn2IsK6rjaxN73LU3fvDoGGO1IZIr4,170
|
|
4
4
|
django_webhook_subscriber/conf.py,sha256=0lFW2L_s_85UIszXnUnnMCdb0iy99WnenPWeixonf-I,1759
|
|
5
|
-
django_webhook_subscriber/delivery.py,sha256=
|
|
5
|
+
django_webhook_subscriber/delivery.py,sha256=VQg2x9lQb49mNRKFK6-INTWaAh6O-IlLwp9nHIzv1vM,15502
|
|
6
6
|
django_webhook_subscriber/http.py,sha256=0CoK1OMm7lCIJ3zzpNH3cdVuIgDnAB4KUqLRM_KRGQs,1191
|
|
7
7
|
django_webhook_subscriber/managers.py,sha256=w2QZCYs858XMlcI-WSZJ0H8vN_IzpTvu5_H3bmiy7zM,2322
|
|
8
8
|
django_webhook_subscriber/models.py,sha256=IdG0eBE3JPUmPLWqpR62GLtA4xVF8caIU92ourgRzVk,11528
|
|
9
|
-
django_webhook_subscriber/serializers.py,sha256=
|
|
9
|
+
django_webhook_subscriber/serializers.py,sha256=1e1rqLLd9v3qiZwKMHJsO4TakF5FXfVc8lqk7QNt7KU,1758
|
|
10
10
|
django_webhook_subscriber/tasks.py,sha256=jlE8Mdor387gcWfHlrMe8OGoegjt2xn8gsVVL8LkHDY,14269
|
|
11
11
|
django_webhook_subscriber/utils.py,sha256=SdogR0VmeMMl7tgl-DD5_4yP7vt3OcgI8IpghoCIVXQ,2950
|
|
12
12
|
django_webhook_subscriber/validators.py,sha256=_qlBi0rS3DaW3jKRhdpnfHzuqupqwaWtiNuZAWpIAkU,1848
|
|
@@ -24,15 +24,15 @@ django_webhook_subscriber/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
|
|
|
24
24
|
django_webhook_subscriber/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
25
|
django_webhook_subscriber/tests/factories.py,sha256=z3fXJqt_3csAFrvM5qdKwzsVu0v_e72racLvMgejEKA,1277
|
|
26
26
|
django_webhook_subscriber/tests/settings.py,sha256=jBy9X7QhmoQ9hnaJk4WDGWXqpRydpHlrROaXU5t7KZI,825
|
|
27
|
-
django_webhook_subscriber/tests/test_delivery.py,sha256=
|
|
27
|
+
django_webhook_subscriber/tests/test_delivery.py,sha256=XWc7BTCXALCXn9uvqFlaQhbHlT1tyAcvQECtajeBfnY,21231
|
|
28
28
|
django_webhook_subscriber/tests/test_http.py,sha256=-zBNRjpYxBDCC5NvWfdYc36aFdzCwN-1p8yuQsLGfz8,1262
|
|
29
29
|
django_webhook_subscriber/tests/test_managers.py,sha256=z_c49z0UjkAnldXy-KU_XoECC66dr7orE77_xFvnM4A,3062
|
|
30
30
|
django_webhook_subscriber/tests/test_models.py,sha256=RHE14IuaMtthiaRZ8g4h2EZ4VilWOrs9UrkArDbvcDg,15209
|
|
31
31
|
django_webhook_subscriber/tests/test_serializers.py,sha256=UuN-cDDmsu8ZFB-aPesffT74Ck6uIuDo9ehkq8y43Mw,1831
|
|
32
32
|
django_webhook_subscriber/tests/test_tasks.py,sha256=wcYlYqrRC9G3C4leEAKrt7x7D1uhlqx9mfwkfQYnb8c,20622
|
|
33
33
|
django_webhook_subscriber/tests/test_utils.py,sha256=zFXDjr81wB8emeJKNjlwA8ezfJTfCMSw46-S2dB_fO0,4279
|
|
34
|
-
django_webhook_subscriber-2.
|
|
35
|
-
django_webhook_subscriber-2.
|
|
36
|
-
django_webhook_subscriber-2.
|
|
37
|
-
django_webhook_subscriber-2.
|
|
38
|
-
django_webhook_subscriber-2.
|
|
34
|
+
django_webhook_subscriber-2.1.0.dist-info/licenses/LICENSE,sha256=Cqe_H97kNjzh70ZIee47TV5t0GQyath_iH2i0Yp47SU,1064
|
|
35
|
+
django_webhook_subscriber-2.1.0.dist-info/METADATA,sha256=pAzJd6R07F-PNfZSM0HbZctK9sL1IIUafynDfVf09r4,18982
|
|
36
|
+
django_webhook_subscriber-2.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
37
|
+
django_webhook_subscriber-2.1.0.dist-info/top_level.txt,sha256=t2_XjlYcTMLR9OfBGdsW0xucs3OeRWrJ7ypETMXqrvw,26
|
|
38
|
+
django_webhook_subscriber-2.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|