Metadata-Version: 2.1
Name: drf-webhooks
Version: 0.1.5
Summary: Setup webhooks using existing DRF Serializers
Home-page: https://github.com/demux/drf-webhooks
License: MIT
Keywords: django,drf,rest,djangorestapi,webhooks
Author: Arnar Yngvason
Author-email: arnar@reon.is
Requires-Python: >=3.10,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Requires-Dist: Django (>=4.1,<5.0)
Requires-Dist: celery (>=5.2,<6.0)
Requires-Dist: djangorestframework (>=3.14,<4.0)
Requires-Dist: djangorestframework-xml (>=2.0,<3.0)
Requires-Dist: httpx (>=0.23,<0.24)
Requires-Dist: inflection (>=0.5,<0.6)
Requires-Dist: pendulum (>=2.1,<3.0)
Requires-Dist: pytimeparse (>=1.1,<2.0)
Requires-Dist: xmltodict (>=0.13,<0.14)
Project-URL: Repository, https://github.com/demux/drf-webhooks
Description-Content-Type: text/markdown

# Django Rest Framework - Webhooks
**Configurable webhooks based on DRF Serializers**

## Goals:
- [x] Use existing DRF Serializers from REST API to serialize data in webhooks
    - [x] Consistent data formatting
    - [x] Reusable OpenAPI schemas
- [x] Configurable webhooks that simply work *(by way of django signals magic)* without the developer having to keep track of where to trigger them
    - [x] Still allow for "manual" triggering of webhooks
        - This is useful because signals aren't always triggered.
        - For example: `QuerySet.update` does not trigger signals
- [x] Disable webhooks using context managers
    - This can be useful when syncing large chunks of data
    - or with a duplex sync (when two systems sync with each other) to avoid endless loops
- [x] **Webhook Signal Session**
    - [x] A context manager gathers all models signals and at the end of the session only triggers the resulting webhooks
        - [x] If a model instance is both `created` and `deleted` within the session, then no webhook is sent for that model instance
        - [x] If a model instance is `created` and then also `updated` within the session, then a `created` event is sent with the data from the last `updated` signal. Only one webhook even is sent
        - [x] If a models instance is `updated` multiple times within the session, then only one webhook event is sent.
    - [x] Middleware wraps each request in **Webhook Signal Session** context
        - **NOTE:** The developer will have to call the context manager in code that runs outside of requests (for example in celery tasks) manually
- [ ] Automatically determine which nested models need to be monitored for changes. Currently this must be done by setting `signal_model_instance_base_getters`


## Example:

```python
from auth.models import User
from core.models import Address, Landlord, RentalUnit, Tenant
from drf_webhooks.utils import ModelSerializerWebhook


class DepositSerializerWebhook(ModelSerializerWebhook):
    serializer_class = DepositSerializer
    base_name = 'core.deposit'

    @staticmethod
    def get_address_instance_base(address):
        tenants = address.tenant_set.all()
        for tenant in tenants:
            yield from tenant.deposits.all()

        unit = getattr(address, "unit", None)
        if unit:
            yield from address.unit.deposits.all()

    # Monitor changes to data in nested serializers:
    signal_model_instance_base_getters = {
        Tenant: lambda x: x.deposits.all(),
        User: lambda x: x.tenant.deposits.all(),
        RentalUnit: lambda x: x.deposits.all(),
        Address: get_address_instance_base,
        Landlord: lambda x: [],  # Not important for this hook
    }

...

class DepositSerializer(serializers.ModelSerializer):
    tenant = TenantSerializer(read_only=True)
    landlord = LandlordSerializer(read_only=True)
    unit = RentalUnitSerializer(read_only=True)

    class Meta:
        model = Deposit
        fields = [
            'id',
            'created',
            'tenant',
            'landlord',
            'unit',
            'date_from',
            'date_to',
            'security_deposit_amount',
            'last_months_rent_amount',
            'fee_rate',
            'fee_amount',
            'status',
            'initiator',
        ]

...
```

