Skip to content

Commit 91dd5e7

Browse files
committed
Introduce Webhook model
1 parent 13002d1 commit 91dd5e7

File tree

3 files changed

+59
-21
lines changed

3 files changed

+59
-21
lines changed

src/apify/__init__.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
from importlib import metadata
22

3+
from apify_shared.consts import WebhookEventType
34
from crawlee.events._types import Event
45

56
from apify._actor import Actor
67
from apify._configuration import Configuration
8+
from apify._models import Webhook
79
from apify._proxy_configuration import ProxyConfiguration, ProxyInfo
810

911
__version__ = metadata.version('apify')
1012

11-
__all__ = ['Actor', 'Event', 'Configuration', 'ProxyConfiguration', 'ProxyInfo', '__version__']
13+
__all__ = [
14+
'Actor',
15+
'Event',
16+
'Configuration',
17+
'ProxyConfiguration',
18+
'ProxyInfo',
19+
'Webhook',
20+
'WebhookEventType',
21+
'__version__',
22+
]

src/apify/_actor.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from typing_extensions import Self
1212

1313
from apify_client import ApifyClientAsync
14-
from apify_shared.consts import ActorEnvVars, ActorExitCodes, ApifyEnvVars, WebhookEventType
14+
from apify_shared.consts import ActorEnvVars, ActorExitCodes, ApifyEnvVars
1515
from apify_shared.utils import ignore_docs, maybe_extract_enum_member_value
1616
from crawlee import service_container
1717
from crawlee.events._types import Event, EventPersistStateData
@@ -32,6 +32,8 @@
3232

3333
from crawlee.proxy_configuration import _NewUrlFunction
3434

35+
from apify._models import Webhook
36+
3537

3638
MainReturnType = TypeVar('MainReturnType')
3739

@@ -533,7 +535,7 @@ async def start(
533535
memory_mbytes: int | None = None,
534536
timeout: timedelta | None = None,
535537
wait_for_finish: int | None = None,
536-
webhooks: list[dict] | None = None,
538+
webhooks: list[Webhook] | None = None,
537539
) -> dict:
538540
"""Run an Actor on the Apify platform.
539541
@@ -555,10 +557,6 @@ async def start(
555557
webhooks: Optional ad-hoc webhooks (https://docs.apify.com/webhooks/ad-hoc-webhooks) associated with
556558
the Actor run which can be used to receive a notification, e.g. when the Actor finished or failed.
557559
If you already have a webhook set up for the Actor or task, you do not have to add it again here.
558-
Each webhook is represented by a dictionary containing these items:
559-
* `event_types`: list of `WebhookEventType` values which trigger the webhook
560-
* `request_url`: URL to which to send the webhook HTTP request
561-
* `payload_template` (optional): Optional template for the request payload
562560
563561
Returns:
564562
Info about the started Actor run
@@ -574,7 +572,9 @@ async def start(
574572
memory_mbytes=memory_mbytes,
575573
timeout_secs=int(timeout.total_seconds()) if timeout is not None else None,
576574
wait_for_finish=wait_for_finish,
577-
webhooks=webhooks,
575+
webhooks=[hook.model_dump(by_alias=True, exclude_unset=True, exclude_defaults=True) for hook in webhooks]
576+
if webhooks
577+
else None,
578578
)
579579

580580
async def abort(
@@ -619,7 +619,7 @@ async def call(
619619
build: str | None = None,
620620
memory_mbytes: int | None = None,
621621
timeout: timedelta | None = None,
622-
webhooks: list[dict] | None = None,
622+
webhooks: list[Webhook] | None = None,
623623
wait: timedelta | None = None,
624624
) -> dict | None:
625625
"""Start an Actor on the Apify Platform and wait for it to finish before returning.
@@ -656,7 +656,9 @@ async def call(
656656
build=build,
657657
memory_mbytes=memory_mbytes,
658658
timeout_secs=int(timeout.total_seconds()) if timeout is not None else None,
659-
webhooks=webhooks,
659+
webhooks=[hook.model_dump(by_alias=True, exclude_defaults=True, exclude_unset=True) for hook in webhooks]
660+
if webhooks
661+
else [],
660662
wait_secs=int(wait.total_seconds()) if wait is not None else None,
661663
)
662664

@@ -668,7 +670,7 @@ async def call_task(
668670
build: str | None = None,
669671
memory_mbytes: int | None = None,
670672
timeout: timedelta | None = None,
671-
webhooks: list[dict] | None = None,
673+
webhooks: list[Webhook] | None = None,
672674
wait: timedelta | None = None,
673675
token: str | None = None,
674676
) -> dict | None:
@@ -708,7 +710,9 @@ async def call_task(
708710
build=build,
709711
memory_mbytes=memory_mbytes,
710712
timeout_secs=int(timeout.total_seconds()) if timeout is not None else None,
711-
webhooks=webhooks,
713+
webhooks=[hook.model_dump(by_alias=True, exclude_defaults=True, exclude_unset=True) for hook in webhooks]
714+
if webhooks
715+
else [],
712716
wait_secs=int(wait.total_seconds()) if wait is not None else None,
713717
)
714718

@@ -796,10 +800,8 @@ async def reboot(
796800

797801
async def add_webhook(
798802
self,
803+
webhook: Webhook,
799804
*,
800-
event_types: list[WebhookEventType],
801-
request_url: str,
802-
payload_template: str | None = None,
803805
ignore_ssl_errors: bool | None = None,
804806
do_not_retry: bool | None = None,
805807
idempotency_key: str | None = None,
@@ -814,9 +816,7 @@ async def add_webhook(
814816
For more information about Apify Actor webhooks, please see the [documentation](https://docs.apify.com/webhooks).
815817
816818
Args:
817-
event_types: List of event types that should trigger the webhook. At least one is required.
818-
request_url: URL that will be invoked once the webhook is triggered.
819-
payload_template: Specification of the payload that will be sent to request_url
819+
webhook: The webhook to be added
820820
ignore_ssl_errors: Whether the webhook should ignore SSL errors returned by request_url
821821
do_not_retry: Whether the webhook should retry sending the payload to request_url upon failure.
822822
idempotency_key: A unique identifier of a webhook. You can use it to ensure that you won't create
@@ -837,9 +837,9 @@ async def add_webhook(
837837

838838
return await self._apify_client.webhooks().create(
839839
actor_run_id=self._configuration.actor_run_id,
840-
event_types=event_types,
841-
request_url=request_url,
842-
payload_template=payload_template,
840+
event_types=webhook.event_types,
841+
request_url=webhook.request_url,
842+
payload_template=webhook.payload_template,
843843
ignore_ssl_errors=ignore_ssl_errors,
844844
do_not_retry=do_not_retry,
845845
idempotency_key=idempotency_key,

src/apify/_models.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# ruff: noqa: TCH001 TCH002 TCH003 (Pydantic)
2+
from __future__ import annotations
3+
4+
from typing import Annotated
5+
6+
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field
7+
8+
from apify_shared.consts import WebhookEventType
9+
from crawlee._utils.urls import validate_http_url
10+
11+
12+
class Webhook(BaseModel):
13+
__model_config__ = ConfigDict(populate_by_name=True)
14+
15+
event_types: Annotated[
16+
list[WebhookEventType],
17+
Field(description='Event types that should trigger the webhook'),
18+
]
19+
request_url: Annotated[
20+
str,
21+
Field(description='URL that the webhook should call'),
22+
BeforeValidator(validate_http_url),
23+
]
24+
payload_template: Annotated[
25+
str | None,
26+
Field(description='Template for the payload sent by the webook'),
27+
] = None

0 commit comments

Comments
 (0)